Merge branch 'main' into GTK-systray
This commit is contained in:
commit
8a07c316ac
|
@ -57,7 +57,7 @@ jobs:
|
|||
get_changes any-code CMakeLists.txt cmake Transmission.xcodeproj libtransmission cli daemon gtk macosx qt utils tests web third-party
|
||||
get_changes our-code CMakeLists.txt cmake Transmission.xcodeproj libtransmission cli daemon gtk macosx qt utils tests web
|
||||
get_changes daemon CMakeLists.txt cmake Transmission.xcodeproj third-party libtransmission daemon
|
||||
get_changes dist dist
|
||||
get_changes dist dist release
|
||||
get_changes docs docs
|
||||
get_changes gtk CMakeLists.txt cmake third-party libtransmission gtk
|
||||
get_changes mac CMakeLists.txt cmake Transmission.xcodeproj third-party libtransmission macosx Transmission.xcodeproj
|
||||
|
@ -227,8 +227,8 @@ jobs:
|
|||
run: |
|
||||
if grep 'warning:' makelog; then exit 1; fi
|
||||
|
||||
macos-11:
|
||||
runs-on: macos-11
|
||||
macos-12:
|
||||
runs-on: macos-12
|
||||
needs: [ what-to-make ]
|
||||
if: ${{ needs.what-to-make.outputs.make-cli == 'true' || needs.what-to-make.outputs.make-daemon == 'true' || needs.what-to-make.outputs.make-gtk == 'true' || needs.what-to-make.outputs.make-mac == 'true' || needs.what-to-make.outputs.make-qt == 'true' || needs.what-to-make.outputs.make-tests == 'true' || needs.what-to-make.outputs.make-utils == 'true' }}
|
||||
steps:
|
||||
|
@ -245,7 +245,7 @@ jobs:
|
|||
run: brew install gtkmm3
|
||||
- name: Get Dependencies (Qt)
|
||||
if: ${{ needs.what-to-make.outputs.make-qt == 'true' }}
|
||||
run: brew install qt@5
|
||||
run: brew install qt
|
||||
- name: Get Source
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
|
@ -260,7 +260,7 @@ jobs:
|
|||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=pfx \
|
||||
-DCMAKE_OSX_ARCHITECTURES='x86_64' \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt@5 \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt \
|
||||
-DENABLE_CLI=${{ (needs.what-to-make.outputs.make-cli == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_DAEMON=${{ (needs.what-to-make.outputs.make-daemon == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_GTK=${{ (needs.what-to-make.outputs.make-gtk == 'true') && 'ON' || 'OFF' }} \
|
||||
|
@ -336,7 +336,6 @@ jobs:
|
|||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=pfx \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt@5 \
|
||||
-DENABLE_CLI=${{ (needs.what-to-make.outputs.make-cli == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_DAEMON=${{ (needs.what-to-make.outputs.make-daemon == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_GTK=${{ (needs.what-to-make.outputs.make-gtk == 'true') && 'ON' || 'OFF' }} \
|
||||
|
@ -500,10 +499,10 @@ jobs:
|
|||
name: source-tarball
|
||||
path: obj/transmission*.tar.*
|
||||
|
||||
macos-11-from-tarball:
|
||||
macos-12-from-tarball:
|
||||
needs: [ make-source-tarball, what-to-make ]
|
||||
if: ${{ needs.what-to-make.outputs.make-cli == 'true' || needs.what-to-make.outputs.make-daemon == 'true' || needs.what-to-make.outputs.make-gtk == 'true' || needs.what-to-make.outputs.make-mac == 'true' || needs.what-to-make.outputs.make-qt == 'true' || needs.what-to-make.outputs.make-tests == 'true' || needs.what-to-make.outputs.make-utils == 'true' }}
|
||||
runs-on: macos-11
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- name: Show Configuration
|
||||
run: |
|
||||
|
@ -518,7 +517,7 @@ jobs:
|
|||
run: brew install gtkmm3
|
||||
- name: Get Dependencies (Qt)
|
||||
if: ${{ needs.what-to-make.outputs.make-qt == 'true' }}
|
||||
run: brew install qt@5
|
||||
run: brew install qt
|
||||
- name: Get Source
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
|
@ -534,7 +533,7 @@ jobs:
|
|||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=pfx \
|
||||
-DCMAKE_OSX_ARCHITECTURES='x86_64' \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt@5 \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt \
|
||||
-DENABLE_CLI=${{ (needs.what-to-make.outputs.make-cli == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_DAEMON=${{ (needs.what-to-make.outputs.make-daemon == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_GTK=${{ (needs.what-to-make.outputs.make-gtk == 'true') && 'ON' || 'OFF' }} \
|
||||
|
@ -771,7 +770,6 @@ jobs:
|
|||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=pfx \
|
||||
-DCMAKE_PREFIX_PATH=`brew --prefix`/opt/qt@5 \
|
||||
-DENABLE_CLI=${{ (needs.what-to-make.outputs.make-cli == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_DAEMON=${{ (needs.what-to-make.outputs.make-daemon == 'true') && 'ON' || 'OFF' }} \
|
||||
-DENABLE_GTK=${{ (needs.what-to-make.outputs.make-gtk == 'true') && 'ON' || 'OFF' }} \
|
||||
|
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository and submodules
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
@ -76,10 +76,17 @@ jobs:
|
|||
xargs -L1 ninja -C _build
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: ${{ matrix.language == 'javascript' }}
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/codeql-config-js.yml
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: ${{ matrix.language == 'cpp' }}
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
- name: Build Project
|
||||
if: ${{ matrix.language == 'cpp' }}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
name: Update copyright year(s)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 1 1 *' # 03:00 AM on January 1
|
||||
workflow_dispatch: # Allows you to run this workflow manually from the Actions tab
|
||||
|
||||
jobs:
|
||||
update-copyright-years:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: FantasticFiasco/action-update-license-year@v3
|
||||
with:
|
||||
prTitle: 'chore: update copyright years'
|
||||
commitTitle: 'chore: update copyright year in COPYING'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: COPYING
|
||||
transform: (?<=Copyright )(?<from>\d{4})?-?(\d{4})?
|
||||
- uses: FantasticFiasco/action-update-license-year@v3
|
||||
with:
|
||||
commitTitle: 'chore: update copyright year in user-facing files (1)'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: |
|
||||
gtk/Application.cc
|
||||
qt/LicenseDialog.ui
|
||||
transform: (?<=Copyright )(?<from>\d{4})?-?(\d{4})
|
||||
- uses: FantasticFiasco/action-update-license-year@v3
|
||||
with:
|
||||
commitTitle: 'chore: update copyright year in user-facing files (2)'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: |
|
||||
macosx/Info.plist
|
||||
macosx/Info.plist.in
|
||||
macosx/*/InfoPlist.strings
|
||||
macosx/QuickLookPlugin/Info.plist.in
|
||||
macosx/QuickLookPlugin/QuickLookPlugin-Info.plist
|
||||
transform: (?<=Copyright © )(?<from>\d{4})?-?(\d{4})
|
||||
- uses: FantasticFiasco/action-update-license-year@v3
|
||||
with:
|
||||
commitTitle: 'chore: update copyright year in cmake/transmission.rc.in'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: cmake/Transmission.rc.in
|
||||
transform: (?<from>\d{4})?-?(\d{4})(?= Transmission Project)
|
|
@ -62,6 +62,7 @@ jobs:
|
|||
- name: Get dependencies
|
||||
run: |
|
||||
set -e # abort if any command fails
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y npm
|
||||
- name: Check for style diffs
|
||||
id: check-for-diffs
|
||||
|
@ -110,9 +111,12 @@ jobs:
|
|||
echo
|
||||
echo Please undo your changes to these files:
|
||||
git diff --exit-code --name-only --merge-base "origin/$GITHUB_BASE_REF" -- \
|
||||
web/public_html/transmission-app.css \
|
||||
web/public_html/transmission-app.css.LEGAL.txt \
|
||||
web/public_html/transmission-app.css.map \
|
||||
web/public_html/transmission-app.js \
|
||||
web/public_html/transmission-app.js.map \
|
||||
web/public_html/transmission-app.js.LICENSE.txt
|
||||
web/public_html/transmission-app.js.LEGAL.txt \
|
||||
web/public_html/transmission-app.js.map
|
||||
|
||||
update-generated-files:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -24,5 +24,11 @@ node_modules/
|
|||
/third-party/suffixes_dafsa.h
|
||||
/web/public_html/transmission-app.js.map
|
||||
|
||||
# clangd compile commands
|
||||
compile_commands.json
|
||||
|
||||
# CLion IDE build directory
|
||||
/cmake-build-*/
|
||||
|
||||
# CMake user presets
|
||||
CMakeUserPresets.json
|
|
@ -50,3 +50,10 @@
|
|||
[submodule "third-party/small"]
|
||||
path = third-party/small
|
||||
url = https://github.com/transmission/small.git
|
||||
[submodule "third-party/rapidjson"]
|
||||
path = third-party/rapidjson
|
||||
url = https://github.com/transmission/rapidjson.git
|
||||
fetchRecurseSubmodules = false
|
||||
[submodule "third-party/rpavlik-cmake-modules"]
|
||||
path = third-party/rpavlik-cmake-modules
|
||||
url = https://github.com/transmission/rpavlik-cmake-modules.git
|
||||
|
|
12
.tx/config
12
.tx/config
|
@ -12,72 +12,84 @@ file_filter = macosx/<lang>.lproj/Localizable.strings
|
|||
source_file = macosx/en.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-AddMagnetWindow]
|
||||
file_filter = macosx/<lang>.lproj/AddMagnetWindow.strings
|
||||
source_file = macosx/en.lproj/AddMagnetWindow.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-AddWindow]
|
||||
file_filter = macosx/<lang>.lproj/AddWindow.strings
|
||||
source_file = macosx/en.lproj/AddWindow.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-Creator]
|
||||
file_filter = macosx/<lang>.lproj/Creator.strings
|
||||
source_file = macosx/en.lproj/Creator.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-GlobalOptionsPopover]
|
||||
file_filter = macosx/<lang>.lproj/GlobalOptionsPopover.strings
|
||||
source_file = macosx/en.lproj/GlobalOptionsPopover.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-GroupRules]
|
||||
file_filter = macosx/<lang>.lproj/GroupRules.strings
|
||||
source_file = macosx/en.lproj/GroupRules.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-InfoActivityView]
|
||||
file_filter = macosx/<lang>.lproj/InfoActivityView.strings
|
||||
source_file = macosx/en.lproj/InfoActivityView.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-InfoGeneralView]
|
||||
file_filter = macosx/<lang>.lproj/InfoGeneralView.strings
|
||||
source_file = macosx/en.lproj/InfoGeneralView.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-InfoOptionsView]
|
||||
file_filter = macosx/<lang>.lproj/InfoOptionsView.strings
|
||||
source_file = macosx/en.lproj/InfoOptionsView.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-MainMenu]
|
||||
file_filter = macosx/<lang>.lproj/MainMenu.strings
|
||||
source_file = macosx/en.lproj/MainMenu.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-PrefsWindow]
|
||||
file_filter = macosx/<lang>.lproj/PrefsWindow.strings
|
||||
source_file = macosx/en.lproj/PrefsWindow.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:mac-ql]
|
||||
file_filter = macosx/QuickLookPlugin/<lang>.lproj/Localizable.strings
|
||||
source_file = macosx/QuickLookPlugin/en.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
type = STRINGS
|
||||
lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-CN, zh_TW: zh-TW
|
||||
|
||||
[o:transmissionbt:p:transmissionbt:r:qt]
|
||||
file_filter = qt/translations/transmission_<lang>.ts
|
||||
|
|
|
@ -20,7 +20,13 @@ endif()
|
|||
|
||||
project(transmission)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
set(TR_THIRD_PARTY_DIR_NAME third-party)
|
||||
set(TR_THIRD_PARTY_SOURCE_DIR ${PROJECT_SOURCE_DIR}/${TR_THIRD_PARTY_DIR_NAME})
|
||||
set(TR_THIRD_PARTY_BINARY_DIR ${PROJECT_BINARY_DIR}/${TR_THIRD_PARTY_DIR_NAME})
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${PROJECT_SOURCE_DIR}/cmake"
|
||||
"${TR_THIRD_PARTY_SOURCE_DIR}/rpavlik-cmake-modules")
|
||||
|
||||
set(CMAKE_MACOSX_RPATH ON)
|
||||
|
||||
|
@ -40,7 +46,7 @@ set(GIOMM_MINIMUM 2.26.0)
|
|||
set(GLIBMM_MINIMUM 2.60.0)
|
||||
set(GTKMM3_MINIMUM 3.24.0)
|
||||
set(GTKMM4_MINIMUM 4.11.1)
|
||||
set(OPENSSL_MINIMUM 0.9.7)
|
||||
set(OPENSSL_MINIMUM 1.1.0)
|
||||
set(MBEDTLS_MINIMUM 1.3)
|
||||
set(NPM_MINIMUM 8.1.307) # Node.js 14
|
||||
set(PSL_MINIMUM 0.21.1)
|
||||
|
@ -142,9 +148,16 @@ else()
|
|||
endif()
|
||||
string(APPEND TR_PEER_ID_PREFIX "-")
|
||||
|
||||
set(TR_VCS_REVISION_FILE "${CMAKE_SOURCE_DIR}/REVISION")
|
||||
set(TR_VCS_REVISION_FILE "${PROJECT_SOURCE_DIR}/REVISION")
|
||||
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/.git)
|
||||
## Compiler standard version
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
find_package(Git)
|
||||
endif()
|
||||
|
||||
|
@ -153,11 +166,9 @@ if(NOT "$ENV{JENKINS_URL}" STREQUAL "" AND NOT "$ENV{GIT_COMMIT}" STREQUAL "")
|
|||
elseif(NOT "$ENV{TEAMCITY_PROJECT_NAME}" STREQUAL "" AND NOT "$ENV{BUILD_VCS_NUMBER}" STREQUAL "")
|
||||
set(TR_VCS_REVISION "$ENV{BUILD_VCS_NUMBER}")
|
||||
elseif(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-list --max-count=1 HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE TR_VCS_REVISION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(TR_REFSPEC TR_VCS_REVISION)
|
||||
unset(TR_REFSPEC)
|
||||
endif()
|
||||
|
||||
if("${TR_VCS_REVISION}" STREQUAL "" AND EXISTS "${TR_VCS_REVISION_FILE}")
|
||||
|
@ -204,9 +215,11 @@ if(WIN32)
|
|||
endforeach()
|
||||
endif()
|
||||
|
||||
set(CMAKE_FOLDER "third-party")
|
||||
set(CMAKE_FOLDER "${TR_THIRD_PARTY_DIR_NAME}")
|
||||
|
||||
find_package(FastFloat)
|
||||
find_package(Fmt)
|
||||
find_package(RapidJSON)
|
||||
find_package(Small)
|
||||
find_package(UtfCpp)
|
||||
find_package(WideInteger)
|
||||
|
@ -215,11 +228,6 @@ find_package(Threads)
|
|||
find_package(PkgConfig QUIET)
|
||||
|
||||
find_package(CURL ${CURL_MINIMUM} REQUIRED)
|
||||
if(NOT TARGET CURL::libcurl)
|
||||
add_library(CURL::libcurl INTERFACE IMPORTED)
|
||||
target_link_libraries(CURL::libcurl INTERFACE ${CURL_LIBRARIES})
|
||||
target_include_directories(CURL::libcurl INTERFACE ${CURL_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(ENABLE_DEPRECATED STREQUAL "AUTO")
|
||||
if(DEFINED ENV{CI})
|
||||
|
@ -456,8 +464,6 @@ if(ENABLE_MAC)
|
|||
tr_fixup_auto_option(ENABLE_MAC MAC_FOUND MAC_IS_REQUIRED)
|
||||
endif()
|
||||
|
||||
set(THIRD_PARTY_DIR ${CMAKE_SOURCE_DIR}/third-party)
|
||||
|
||||
if(WIN32 AND NOT MINGW)
|
||||
set(DEFLATE_LIB_NAME deflatestatic)
|
||||
else()
|
||||
|
@ -507,8 +513,7 @@ target_compile_definitions(miniupnpc::libminiupnpc
|
|||
SYSTEM_MINIUPNP
|
||||
$<$<VERSION_LESS:${MINIUPNPC_VERSION},1.7>:MINIUPNPC_API_VERSION=${MINIUPNPC_API_VERSION}>) # API version macro was only added in 1.7
|
||||
|
||||
add_subdirectory(third-party/jsonsl)
|
||||
add_subdirectory(third-party/wildmat)
|
||||
add_subdirectory(${TR_THIRD_PARTY_SOURCE_DIR}/wildmat)
|
||||
|
||||
tr_add_external_auto_library(DHT dht dht
|
||||
TARGET dht::dht)
|
||||
|
@ -530,7 +535,7 @@ tr_add_external_auto_library(B64 libb64 b64
|
|||
CMAKE_ARGS
|
||||
-DLIBB64_SHARED:BOOL=OFF)
|
||||
|
||||
set(TR_WEB_ASSETS ${CMAKE_SOURCE_DIR}/web/public_html)
|
||||
set(TR_WEB_ASSETS ${PROJECT_SOURCE_DIR}/web/public_html)
|
||||
if(NOT ${REBUILD_WEB} STREQUAL "OFF")
|
||||
find_program(NPM npm)
|
||||
if ("${NPM}" STREQUAL "NPM-NOTFOUND")
|
||||
|
@ -599,13 +604,6 @@ endif()
|
|||
|
||||
unset(CMAKE_FOLDER)
|
||||
|
||||
## Compiler standard version
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
### Compiler Warnings
|
||||
|
||||
set(C_WARNING_FLAGS)
|
||||
|
@ -830,7 +828,7 @@ if(NOT TR_STABLE_RELEASE AND NOT "${TR_VCS_REVISION}" STREQUAL "")
|
|||
string(APPEND CPACK_SOURCE_PACKAGE_FILE_NAME "+r${TR_VCS_REVISION}")
|
||||
endif()
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
"[.]git"
|
||||
"node_modules")
|
||||
|
||||
|
@ -839,17 +837,17 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES
|
|||
if(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" rev-parse --show-toplevel
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE TR_GIT_ROOT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(TR_GIT_ROOT AND IS_DIRECTORY "${TR_GIT_ROOT}/.git")
|
||||
configure_file("${CMAKE_SOURCE_DIR}/extras/pre-commit" "${TR_GIT_ROOT}/.git/hooks/pre-commit" COPYONLY)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/extras/pre-commit" "${TR_GIT_ROOT}/.git/hooks/pre-commit" COPYONLY)
|
||||
add_custom_target(check-format
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/code_style.sh" --check
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/code_style.sh" --check
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}")
|
||||
add_custom_target(format
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/code_style.sh"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/code_style.sh"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}")
|
||||
set_property(
|
||||
TARGET check-format format
|
||||
PROPERTY FOLDER "utility")
|
||||
|
|
2
COPYING
2
COPYING
|
@ -1,4 +1,4 @@
|
|||
Copyright 2005-2023. All code is copyrighted by the respective authors.
|
||||
Copyright 2005-2024. All code is copyrighted by the respective authors.
|
||||
|
||||
Transmission can be redistributed and/or modified under the terms of
|
||||
the GNU GPLv2 (http://www.gnu.org/licenses/license-list.html#GPLv2),
|
||||
|
|
58
README.md
58
README.md
|
@ -31,15 +31,16 @@ For a more detailed description, and dependencies, visit [How to Build Transmiss
|
|||
|
||||
### Building a Transmission release from the command line
|
||||
|
||||
$ tar xf transmission-3.00.tar.xz
|
||||
$ cd transmission-3.00
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
```bash
|
||||
$ tar xf transmission-4.0.4.tar.xz
|
||||
$ cd transmission-4.0.4
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
$ cd build
|
||||
$ cmake --build .
|
||||
$ sudo cmake --install .
|
||||
```
|
||||
|
||||
### Building Transmission from the nightly builds
|
||||
|
||||
|
@ -49,29 +50,28 @@ If you're new to building programs from source code, this is typically easier th
|
|||
|
||||
### Building Transmission from Git (first time)
|
||||
|
||||
$ git clone https://github.com/transmission/transmission Transmission
|
||||
$ cd Transmission
|
||||
$ git submodule update --init --recursive
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
```bash
|
||||
$ git clone --recurse-submodules https://github.com/transmission/transmission Transmission
|
||||
$ cd Transmission
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
$ cd build
|
||||
$ cmake --build .
|
||||
$ sudo cmake --install .
|
||||
```
|
||||
|
||||
### Building Transmission from Git (updating)
|
||||
|
||||
$ cd Transmission/build
|
||||
$ make clean
|
||||
$ git submodule foreach --recursive git clean -xfd
|
||||
$ git pull --rebase --prune
|
||||
$ git submodule update --init --recursive
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
```bash
|
||||
$ cd Transmission/build
|
||||
$ cmake --build . -t clean
|
||||
$ git submodule foreach --recursive git clean -xfd
|
||||
$ git pull --rebase --prune
|
||||
$ git submodule update --init --recursive
|
||||
$ cmake --build .
|
||||
$ sudo cmake --install .
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
357
cli/cli.cc
357
cli/cli.cc
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2006-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
@ -19,57 +19,36 @@
|
|||
#include <libtransmission/file.h>
|
||||
#include <libtransmission/tr-getopt.h>
|
||||
#include <libtransmission/utils.h> // _()
|
||||
#include <libtransmission/values.h>
|
||||
#include <libtransmission/variant.h>
|
||||
#include <libtransmission/version.h>
|
||||
#include <libtransmission/web-utils.h>
|
||||
#include <libtransmission/web.h> // tr_sessionFetch()
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
static auto constexpr MemK = size_t{ 1024 };
|
||||
static char constexpr MemKStr[] = "KiB";
|
||||
static char constexpr MemMStr[] = "MiB";
|
||||
static char constexpr MemGStr[] = "GiB";
|
||||
static char constexpr MemTStr[] = "TiB";
|
||||
|
||||
static auto constexpr DiskK = size_t{ 1000 };
|
||||
static char constexpr DiskKStr[] = "kB";
|
||||
static char constexpr DiskMStr[] = "MB";
|
||||
static char constexpr DiskGStr[] = "GB";
|
||||
static char constexpr DiskTStr[] = "TB";
|
||||
|
||||
static auto constexpr SpeedK = size_t{ 1000 };
|
||||
#define SPEED_K_STR "kB/s"
|
||||
static char constexpr SpeedKStr[] = SPEED_K_STR;
|
||||
static char constexpr SpeedMStr[] = "MB/s";
|
||||
static char constexpr SpeedGStr[] = "GB/s";
|
||||
static char constexpr SpeedTStr[] = "TB/s";
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
namespace
|
||||
{
|
||||
auto constexpr LineWidth = int{ 80 };
|
||||
|
||||
static auto constexpr LineWidth = int{ 80 };
|
||||
|
||||
static char constexpr MyConfigName[] = "transmission";
|
||||
static char constexpr MyReadableName[] = "transmission-cli";
|
||||
static char constexpr Usage
|
||||
char constexpr MyConfigName[] = "transmission";
|
||||
char constexpr MyReadableName[] = "transmission-cli";
|
||||
char constexpr Usage
|
||||
[] = "A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"Usage: transmission-cli [options] <file|url|magnet>";
|
||||
|
||||
static bool showVersion = false;
|
||||
static bool verify = false;
|
||||
static sig_atomic_t gotsig = false;
|
||||
static sig_atomic_t manualUpdate = false;
|
||||
bool showVersion = false;
|
||||
bool verify = false;
|
||||
sig_atomic_t gotsig = false;
|
||||
sig_atomic_t manualUpdate = false;
|
||||
|
||||
static char const* torrentPath = nullptr;
|
||||
char const* torrentPath = nullptr;
|
||||
|
||||
static auto constexpr Options = std::array<tr_option, 20>{
|
||||
auto constexpr Options = std::array<tr_option, 20>{
|
||||
{ { 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
{ 'd', "downlimit", "Set max download speed in " SPEED_K_STR, "d", true, "<speed>" },
|
||||
|
@ -99,11 +78,11 @@ static auto constexpr Options = std::array<tr_option, 20>{
|
|||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
static int parseCommandLine(tr_variant*, int argc, char const** argv);
|
||||
int parseCommandLine(tr_variant*, int argc, char const** argv);
|
||||
|
||||
static void sigHandler(int signal);
|
||||
void sigHandler(int signal);
|
||||
|
||||
static std::string tr_strlratio(double ratio)
|
||||
[[nodiscard]] std::string tr_strlratio(double ratio)
|
||||
{
|
||||
if (static_cast<int>(ratio) == TR_RATIO_NA)
|
||||
{
|
||||
|
@ -117,27 +96,27 @@ static std::string tr_strlratio(double ratio)
|
|||
|
||||
if (ratio < 10.0)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:.2f}"), ratio);
|
||||
return fmt::format("{:.2f}", ratio);
|
||||
}
|
||||
|
||||
if (ratio < 100.0)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:.1f}"), ratio);
|
||||
return fmt::format("{:.1f}", ratio);
|
||||
}
|
||||
|
||||
return fmt::format(FMT_STRING("{:.0f}"), ratio);
|
||||
return fmt::format("{:.0f}", ratio);
|
||||
}
|
||||
|
||||
static bool waitingOnWeb;
|
||||
bool waitingOnWeb;
|
||||
|
||||
static void onTorrentFileDownloaded(tr_web::FetchResponse const& response)
|
||||
void onTorrentFileDownloaded(tr_web::FetchResponse const& response)
|
||||
{
|
||||
auto* ctor = static_cast<tr_ctor*>(response.user_data);
|
||||
tr_ctorSetMetainfo(ctor, std::data(response.body), std::size(response.body), nullptr);
|
||||
waitingOnWeb = false;
|
||||
}
|
||||
|
||||
static std::string getStatusStr(tr_stat const* st)
|
||||
[[nodiscard]] std::string getStatusStr(tr_stat const* st)
|
||||
{
|
||||
if (st->activity == TR_STATUS_CHECK_WAIT)
|
||||
{
|
||||
|
@ -147,7 +126,7 @@ static std::string getStatusStr(tr_stat const* st)
|
|||
if (st->activity == TR_STATUS_CHECK)
|
||||
{
|
||||
return fmt::format(
|
||||
FMT_STRING("Verifying local files ({:.2f}%, {:.2f}% valid)"),
|
||||
"Verifying local files ({:.2f}%, {:.2f}% valid)",
|
||||
tr_truncd(100 * st->recheckProgress, 2),
|
||||
tr_truncd(100 * st->percentDone, 2));
|
||||
}
|
||||
|
@ -155,30 +134,30 @@ static std::string getStatusStr(tr_stat const* st)
|
|||
if (st->activity == TR_STATUS_DOWNLOAD)
|
||||
{
|
||||
return fmt::format(
|
||||
FMT_STRING("Progress: {:.1f}%, dl from {:d} of {:d} peers ({:s}), ul to {:d} ({:s}) [{:s}]"),
|
||||
"Progress: {:.1f}%, dl from {:d} of {:d} peers ({:s}), ul to {:d} ({:s}) [{:s}]",
|
||||
tr_truncd(100 * st->percentDone, 1),
|
||||
st->peersSendingToUs,
|
||||
st->peersConnected,
|
||||
tr_formatter_speed_KBps(st->pieceDownloadSpeed_KBps),
|
||||
Speed{ st->pieceDownloadSpeed_KBps, Speed::Units::KByps }.to_string(),
|
||||
st->peersGettingFromUs,
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps),
|
||||
Speed{ st->pieceUploadSpeed_KBps, Speed::Units::KByps }.to_string(),
|
||||
tr_strlratio(st->ratio));
|
||||
}
|
||||
|
||||
if (st->activity == TR_STATUS_SEED)
|
||||
{
|
||||
return fmt::format(
|
||||
FMT_STRING("Seeding, uploading to {:d} of {:d} peer(s), {:s} [{:s}]"),
|
||||
"Seeding, uploading to {:d} of {:d} peer(s), {:s} [{:s}]",
|
||||
st->peersGettingFromUs,
|
||||
st->peersConnected,
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps),
|
||||
Speed{ st->pieceUploadSpeed_KBps, Speed::Units::KByps }.to_string(),
|
||||
tr_strlratio(st->ratio));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getConfigDir(int argc, char const** argv)
|
||||
[[nodiscard]] std::string getConfigDir(int argc, char const** argv)
|
||||
{
|
||||
int c;
|
||||
char const* my_optarg;
|
||||
|
@ -198,16 +177,139 @@ static std::string getConfigDir(int argc, char const** argv)
|
|||
return tr_getDefaultConfigDir(MyConfigName);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
int parseCommandLine(tr_variant* d, int argc, char const** argv)
|
||||
{
|
||||
int c;
|
||||
char const* my_optarg;
|
||||
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &my_optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'b':
|
||||
tr_variantDictAddBool(d, TR_KEY_blocklist_enabled, true);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
tr_variantDictAddBool(d, TR_KEY_blocklist_enabled, false);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_down, atoi(my_optarg));
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_down_enabled, true);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_down_enabled, false);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
tr_variantDictAddStr(d, TR_KEY_script_torrent_done_filename, my_optarg);
|
||||
tr_variantDictAddBool(d, TR_KEY_script_torrent_done_enabled, true);
|
||||
break;
|
||||
|
||||
case 'g': /* handled above */
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, true);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, false);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
tr_variantDictAddInt(d, TR_KEY_peer_port, atoi(my_optarg));
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, my_optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_up, atoi(my_optarg));
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, true);
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, false);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verify = true;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
showVersion = true;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
tr_variantDictAddStr(d, TR_KEY_download_dir, my_optarg);
|
||||
break;
|
||||
|
||||
case 910:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
|
||||
break;
|
||||
|
||||
case 911:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
|
||||
break;
|
||||
|
||||
case 912:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_CLEAR_PREFERRED);
|
||||
break;
|
||||
|
||||
case 500:
|
||||
tr_variantDictAddBool(d, TR_KEY_sequentialDownload, true);
|
||||
break;
|
||||
|
||||
case TR_OPT_UNK:
|
||||
if (torrentPath == nullptr)
|
||||
{
|
||||
torrentPath = my_optarg;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sigHandler(int signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT:
|
||||
gotsig = true;
|
||||
break;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
case SIGHUP:
|
||||
manualUpdate = true;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int tr_main(int argc, char* argv[])
|
||||
{
|
||||
auto const init_mgr = tr_lib_init();
|
||||
|
||||
tr_locale_set_global("");
|
||||
|
||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||
tr_formatter_size_init(DiskK, DiskKStr, DiskMStr, DiskGStr, DiskTStr);
|
||||
tr_formatter_speed_init(SpeedK, SpeedKStr, SpeedMStr, SpeedGStr, SpeedTStr);
|
||||
|
||||
printf("%s %s\n", MyReadableName, LONG_VERSION_STRING);
|
||||
|
||||
/* user needs to pass in at least one argument */
|
||||
|
@ -219,7 +321,7 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
/* load the defaults from config file + libtransmission defaults */
|
||||
auto const config_dir = getConfigDir(argc, (char const**)argv);
|
||||
auto settings = tr_sessionLoadSettings(config_dir.c_str(), MyConfigName);
|
||||
auto settings = tr_sessionLoadSettings(nullptr, config_dir.c_str(), MyConfigName);
|
||||
|
||||
/* the command line overrides defaults */
|
||||
if (parseCommandLine(&settings, argc, (char const**)argv) != 0)
|
||||
|
@ -245,12 +347,14 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
if (!tr_sys_path_exists(sz_download_dir))
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
|
||||
if (!tr_sys_dir_create(sz_download_dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error))
|
||||
if (auto error = tr_error{}; !tr_sys_dir_create(sz_download_dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error) && error)
|
||||
{
|
||||
fprintf(stderr, "Unable to create download directory \"%s\": %s\n", sz_download_dir.c_str(), error->message);
|
||||
tr_error_free(error);
|
||||
auto const errmsg = fmt::format(
|
||||
"Couldn't create '{path}': {error} ({error_code})",
|
||||
fmt::arg("path", sz_download_dir),
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code()));
|
||||
fmt::print(stderr, "{:s}\n", errmsg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -360,132 +464,3 @@ int tr_main(int argc, char* argv[])
|
|||
tr_sessionClose(h);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
****
|
||||
***/
|
||||
|
||||
static int parseCommandLine(tr_variant* d, int argc, char const** argv)
|
||||
{
|
||||
int c;
|
||||
char const* my_optarg;
|
||||
|
||||
while ((c = tr_getopt(Usage, argc, argv, std::data(Options), &my_optarg)) != TR_OPT_DONE)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'b':
|
||||
tr_variantDictAddBool(d, TR_KEY_blocklist_enabled, true);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
tr_variantDictAddBool(d, TR_KEY_blocklist_enabled, false);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_down, atoi(my_optarg));
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_down_enabled, true);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_down_enabled, false);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
tr_variantDictAddStr(d, TR_KEY_script_torrent_done_filename, my_optarg);
|
||||
tr_variantDictAddBool(d, TR_KEY_script_torrent_done_enabled, true);
|
||||
break;
|
||||
|
||||
case 'g': /* handled above */
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, true);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, false);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
tr_variantDictAddInt(d, TR_KEY_peer_port, atoi(my_optarg));
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, my_optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
tr_variantDictAddInt(d, TR_KEY_speed_limit_up, atoi(my_optarg));
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, true);
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
tr_variantDictAddBool(d, TR_KEY_speed_limit_up_enabled, false);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verify = true;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
showVersion = true;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
tr_variantDictAddStr(d, TR_KEY_download_dir, my_optarg);
|
||||
break;
|
||||
|
||||
case 910:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_ENCRYPTION_REQUIRED);
|
||||
break;
|
||||
|
||||
case 911:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_ENCRYPTION_PREFERRED);
|
||||
break;
|
||||
|
||||
case 912:
|
||||
tr_variantDictAddInt(d, TR_KEY_encryption, TR_CLEAR_PREFERRED);
|
||||
break;
|
||||
|
||||
case 500:
|
||||
tr_variantDictAddBool(d, TR_KEY_sequentialDownload, true);
|
||||
break;
|
||||
|
||||
case TR_OPT_UNK:
|
||||
if (torrentPath == nullptr)
|
||||
{
|
||||
torrentPath = my_optarg;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigHandler(int signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT:
|
||||
gotsig = true;
|
||||
break;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
case SIGHUP:
|
||||
manualUpdate = true;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@ add_library(FastFloat::fast_float INTERFACE IMPORTED)
|
|||
|
||||
target_include_directories(FastFloat::fast_float
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third-party/fast_float/include)
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/fast_float/include)
|
||||
|
|
|
@ -2,7 +2,7 @@ add_library(fmt::fmt-header-only INTERFACE IMPORTED)
|
|||
|
||||
target_include_directories(fmt::fmt-header-only
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third-party/fmt/include)
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/fmt/include)
|
||||
|
||||
target_compile_definitions(fmt::fmt-header-only
|
||||
INTERFACE
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
add_library(RapidJSON INTERFACE IMPORTED)
|
||||
|
||||
target_include_directories(RapidJSON
|
||||
INTERFACE
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/rapidjson/include)
|
||||
|
||||
target_compile_definitions(RapidJSON
|
||||
INTERFACE
|
||||
RAPIDJSON_HAS_STDSTRING=1)
|
|
@ -2,10 +2,8 @@ add_library(small::small INTERFACE IMPORTED)
|
|||
|
||||
target_include_directories(small::small
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third-party/small/include)
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/small/include)
|
||||
|
||||
|
||||
target_compile_definitions(fmt::fmt-header-only
|
||||
target_compile_definitions(small::small
|
||||
INTERFACE
|
||||
SMALL_DISABLE_EXCEPTIONS=1)
|
||||
|
||||
|
|
|
@ -2,4 +2,4 @@ add_library(utf8::cpp INTERFACE IMPORTED)
|
|||
|
||||
target_include_directories(utf8::cpp
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third-party/utfcpp/source)
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/utfcpp/source)
|
||||
|
|
|
@ -2,4 +2,4 @@ add_library(WideInteger::WideInteger INTERFACE IMPORTED)
|
|||
|
||||
target_include_directories(WideInteger::WideInteger
|
||||
INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third-party/wide-integer)
|
||||
${TR_THIRD_PARTY_SOURCE_DIR}/wide-integer)
|
||||
|
|
|
@ -88,10 +88,10 @@ macro(tr_eval SCRIPT)
|
|||
|
||||
string(SHA1 _TR_EVAL_TMP_FILE "${_TR_EVAL_SCRIPT}")
|
||||
string(SUBSTRING "${_TR_EVAL_TMP_FILE}" 0 10 _TR_EVAL_TMP_FILE)
|
||||
set(_TR_EVAL_TMP_FILE "${CMAKE_BINARY_DIR}/.tr-cache/tr_eval.${_TR_EVAL_TMP_FILE}.cmake")
|
||||
set(_TR_EVAL_TMP_FILE "${PROJECT_BINARY_DIR}/.tr-cache/tr_eval.${_TR_EVAL_TMP_FILE}.cmake")
|
||||
|
||||
if(NOT EXISTS "${_TR_EVAL_TMP_FILE}")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/.tr-cache")
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/.tr-cache")
|
||||
file(WRITE "${_TR_EVAL_TMP_FILE}" "${_TR_EVAL_SCRIPT}")
|
||||
endif()
|
||||
|
||||
|
@ -145,10 +145,10 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
|
|||
set(${CMAKE_MATCH_1} ${CMAKE_MATCH_3} CACHE INTERNAL "")
|
||||
endif()
|
||||
endforeach()
|
||||
add_subdirectory("${CMAKE_SOURCE_DIR}/third-party/${DIRNAME}" "${CMAKE_BINARY_DIR}/third-party/${DIRNAME}.bld")
|
||||
add_subdirectory("${TR_THIRD_PARTY_SOURCE_DIR}/${DIRNAME}" "${TR_THIRD_PARTY_BINARY_DIR}/${DIRNAME}.bld")
|
||||
else()
|
||||
set(${ID}_UPSTREAM_TARGET ${LIBNAME})
|
||||
set(${ID}_PREFIX "${CMAKE_BINARY_DIR}/third-party/${DIRNAME}.bld/pfx")
|
||||
set(${ID}_PREFIX "${TR_THIRD_PARTY_BINARY_DIR}/${DIRNAME}.bld/pfx")
|
||||
|
||||
set(${ID}_INCLUDE_DIR "${${ID}_PREFIX}/include"
|
||||
CACHE INTERNAL "")
|
||||
|
@ -169,8 +169,8 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
|
|||
|
||||
ExternalProject_Add(
|
||||
${${ID}_UPSTREAM_TARGET}
|
||||
PREFIX "${CMAKE_BINARY_DIR}/third-party/${DIRNAME}.bld"
|
||||
SOURCE_DIR "${CMAKE_SOURCE_DIR}/third-party/${DIRNAME}"
|
||||
PREFIX "${TR_THIRD_PARTY_BINARY_DIR}/${DIRNAME}.bld"
|
||||
SOURCE_DIR "${TR_THIRD_PARTY_SOURCE_DIR}/${DIRNAME}"
|
||||
INSTALL_DIR "${${ID}_PREFIX}"
|
||||
CMAKE_ARGS
|
||||
-Wno-dev # We don't want to be warned over unused variables
|
||||
|
@ -188,7 +188,7 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
|
|||
${_TAEAL_ARG_CMAKE_ARGS}
|
||||
BUILD_BYPRODUCTS "${${ID}_LIBRARY}")
|
||||
|
||||
set_property(TARGET ${${ID}_UPSTREAM_TARGET} PROPERTY FOLDER "third-party")
|
||||
set_property(TARGET ${${ID}_UPSTREAM_TARGET} PROPERTY FOLDER "${TR_THIRD_PARTY_DIR_NAME}")
|
||||
|
||||
# Imported target (below) requires include directories to be present at configuration time
|
||||
file(MAKE_DIRECTORY ${${ID}_INCLUDE_DIRS})
|
||||
|
@ -275,7 +275,7 @@ function(tr_win32_app_info TGT DESCR INTNAME ORIGFNAME)
|
|||
set(TR_MAIN_ICON "${ARGN}")
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/Transmission.rc.in" "${INTNAME}-app-info.rc")
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/Transmission.rc.in" "${INTNAME}-app-info.rc")
|
||||
|
||||
target_sources(${TGT}
|
||||
PRIVATE
|
||||
|
@ -437,7 +437,7 @@ function(tr_gettext_msgfmt TGT OUTPUT_FILE INPUT_FILE)
|
|||
|
||||
add_custom_command(
|
||||
OUTPUT ${OUTPUT_FILE}
|
||||
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${MODE_ARG} -d ${CMAKE_SOURCE_DIR}/po --template ${INPUT_FILE} -o ${OUTPUT_FILE}
|
||||
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${MODE_ARG} -d ${PROJECT_SOURCE_DIR}/po --template ${INPUT_FILE} -o ${OUTPUT_FILE}
|
||||
DEPENDS ${INPUT_FILE}
|
||||
VERBATIM)
|
||||
|
||||
|
@ -471,7 +471,7 @@ function(tr_wrap_idl TGT INPUT_FILE OUTPUT_FILE_BASE)
|
|||
DEPENDS ${INPUT_FILE}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
configure_file("${CMAKE_SOURCE_DIR}/cmake/Transmission.tlb.rc.in" ${OUTPUT_FILE_BASE}.tlb.rc)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/Transmission.tlb.rc.in" ${OUTPUT_FILE_BASE}.tlb.rc)
|
||||
|
||||
target_sources(${TGT}
|
||||
PRIVATE
|
||||
|
|
|
@ -32,7 +32,7 @@ BEGIN
|
|||
VALUE "FileDescription", "${TR_FILE_DESCRIPTION}"
|
||||
VALUE "FileVersion", LONG_VERSION_STRING
|
||||
VALUE "InternalName", "${TR_INTERNAL_NAME}"
|
||||
VALUE "LegalCopyright", "2005-2022 Transmission Project"
|
||||
VALUE "LegalCopyright", "2005-2024 Transmission Project"
|
||||
VALUE "OriginalFilename", "${TR_ORIGINAL_FILENAME}"
|
||||
VALUE "ProductName", "Transmission"
|
||||
VALUE "ProductVersion", LONG_VERSION_STRING
|
||||
|
|
|
@ -52,4 +52,10 @@ foreach(P daemon)
|
|||
FILES ${TR_NAME}-${P}.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
if (WITH_SYSTEMD)
|
||||
install(
|
||||
FILES ${TR_NAME}-${P}.service
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/system)
|
||||
endif()
|
||||
endforeach()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2015-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -24,9 +24,9 @@
|
|||
|
||||
#include "daemon.h"
|
||||
|
||||
static void set_system_error(tr_error** error, int code, std::string_view message)
|
||||
static void set_system_error(tr_error& error, int code, std::string_view message)
|
||||
{
|
||||
tr_error_set(error, code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code));
|
||||
error.set(code, fmt::format("{:s}: {:s} ({:d}", message, tr_strerror(code), code));
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_SIGNALFD_H
|
||||
|
@ -131,7 +131,7 @@ void tr_daemon::cleanup_signals(struct event* sig_ev) const
|
|||
#endif /* HAVE_SYS_SIGNALFD_H */
|
||||
}
|
||||
|
||||
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error)
|
||||
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error& error)
|
||||
{
|
||||
*exit_code = 1;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2015-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -23,27 +23,29 @@
|
|||
#define SERVICE_CONTROL_PRESHUTDOWN 0x0000000F
|
||||
#endif
|
||||
|
||||
static LPCWSTR const service_name = L"TransmissionDaemon";
|
||||
namespace
|
||||
{
|
||||
LPCWSTR constexpr service_name = L"TransmissionDaemon";
|
||||
|
||||
// If we can get rid of this global variable...
|
||||
static tr_daemon* daemon;
|
||||
|
||||
// ...these becomes a good candidates for being converted to 'class tr_daemon' members.
|
||||
static SERVICE_STATUS_HANDLE status_handle = nullptr;
|
||||
static DWORD current_state = SERVICE_STOPPED;
|
||||
static HANDLE service_thread = nullptr;
|
||||
static HANDLE service_stop_thread = nullptr;
|
||||
SERVICE_STATUS_HANDLE status_handle = nullptr;
|
||||
DWORD current_state = SERVICE_STOPPED;
|
||||
HANDLE service_thread = nullptr;
|
||||
HANDLE service_stop_thread = nullptr;
|
||||
|
||||
static void set_system_error(tr_error** error, DWORD code, char const* message)
|
||||
void set_system_error(tr_error& error, DWORD code, char const* message)
|
||||
{
|
||||
auto const system_message = tr_win32_format_message(code);
|
||||
tr_error_set(error, code, fmt::format(FMT_STRING("{:s} ({:#08x}): {:s})"), message, code, system_message));
|
||||
error.set(code, fmt::format("{:s} ({:#08x}): {:s})", message, code, system_message));
|
||||
}
|
||||
|
||||
static void do_log_system_error(char const* file, int line, tr_log_level level, DWORD code, char const* message)
|
||||
void do_log_system_error(char const* file, int line, tr_log_level level, DWORD code, char const* message)
|
||||
{
|
||||
auto const system_message = tr_win32_format_message(code);
|
||||
tr_logAddMessage(file, line, level, "tr_daemon", fmt::format("[tr_daemon] {} ({:#x}): {}", message, code, system_message));
|
||||
tr_logAddMessage(file, line, level, fmt::format("{} ({:#x}): {}", message, code, system_message), "tr_daemon");
|
||||
}
|
||||
|
||||
#define log_system_error(level, code, message) \
|
||||
|
@ -57,13 +59,13 @@ static void do_log_system_error(char const* file, int line, tr_log_level level,
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static BOOL WINAPI handle_console_ctrl(DWORD /*control_type*/)
|
||||
BOOL WINAPI handle_console_ctrl(DWORD /*control_type*/)
|
||||
{
|
||||
daemon->stop();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void update_service_status(
|
||||
void update_service_status(
|
||||
DWORD new_state,
|
||||
DWORD win32_exit_code,
|
||||
DWORD service_specific_exit_code,
|
||||
|
@ -91,7 +93,7 @@ static void update_service_status(
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int __stdcall service_stop_thread_main(void* param)
|
||||
unsigned int __stdcall service_stop_thread_main(void* param)
|
||||
{
|
||||
daemon->stop();
|
||||
|
||||
|
@ -107,7 +109,7 @@ static unsigned int __stdcall service_stop_thread_main(void* param)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void stop_service(void)
|
||||
void stop_service(void)
|
||||
{
|
||||
if (service_stop_thread != nullptr)
|
||||
{
|
||||
|
@ -128,7 +130,7 @@ static void stop_service(void)
|
|||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/, LPVOID /*event_data*/, LPVOID /*context*/)
|
||||
DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/, LPVOID /*event_data*/, LPVOID /*context*/)
|
||||
{
|
||||
switch (control_code)
|
||||
{
|
||||
|
@ -150,12 +152,12 @@ static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/
|
|||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static unsigned int __stdcall service_thread_main(void* /*context*/)
|
||||
unsigned int __stdcall service_thread_main(void* /*context*/)
|
||||
{
|
||||
return daemon->start(false);
|
||||
}
|
||||
|
||||
static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
||||
VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
||||
{
|
||||
status_handle = RegisterServiceCtrlHandlerExW(service_name, &handle_service_ctrl, nullptr);
|
||||
|
||||
|
@ -199,6 +201,7 @@ static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/)
|
|||
|
||||
update_service_status(SERVICE_STOPPED, NO_ERROR, exit_code, 0, 0);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool tr_daemon::setup_signals([[maybe_unused]] struct event*& sig_ev)
|
||||
{
|
||||
|
@ -209,7 +212,7 @@ void tr_daemon::cleanup_signals([[maybe_unused]] struct event* sig_ev) const
|
|||
{
|
||||
}
|
||||
|
||||
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error** error)
|
||||
bool tr_daemon::spawn(bool foreground, int* exit_code, tr_error& error)
|
||||
{
|
||||
daemon = this;
|
||||
|
||||
|
|
270
daemon/daemon.cc
270
daemon/daemon.cc
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -6,7 +6,6 @@
|
|||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstdio> /* printf */
|
||||
#include <cstdlib> /* atoi */
|
||||
#include <iostream>
|
||||
#include <iterator> /* std::back_inserter */
|
||||
#include <memory>
|
||||
|
@ -33,6 +32,7 @@
|
|||
#include <libtransmission/error.h>
|
||||
#include <libtransmission/file.h>
|
||||
#include <libtransmission/log.h>
|
||||
#include <libtransmission/quark.h>
|
||||
#include <libtransmission/timer-ev.h>
|
||||
#include <libtransmission/tr-getopt.h>
|
||||
#include <libtransmission/tr-strbuf.h>
|
||||
|
@ -62,39 +62,21 @@ struct tr_torrent;
|
|||
using namespace std::literals;
|
||||
using libtransmission::Watchdir;
|
||||
|
||||
static char constexpr MyName[] = "transmission-daemon";
|
||||
static char constexpr Usage[] = "Transmission " LONG_VERSION_STRING
|
||||
" https://transmissionbt.com/\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"transmission-daemon is a headless Transmission session that can be\n"
|
||||
"controlled via transmission-qt, transmission-remote, or its web interface.\n"
|
||||
"\n"
|
||||
"Usage: transmission-daemon [options]";
|
||||
namespace
|
||||
{
|
||||
char constexpr MyName[] = "transmission-daemon";
|
||||
char constexpr Usage[] = "Transmission " LONG_VERSION_STRING
|
||||
" https://transmissionbt.com/\n"
|
||||
"A fast and easy BitTorrent client\n"
|
||||
"\n"
|
||||
"transmission-daemon is a headless Transmission session that can be\n"
|
||||
"controlled via transmission-qt, transmission-remote, or its web interface.\n"
|
||||
"\n"
|
||||
"Usage: transmission-daemon [options]";
|
||||
|
||||
static auto constexpr MemK = size_t{ 1024 };
|
||||
static char constexpr MemKStr[] = "KiB";
|
||||
static char constexpr MemMStr[] = "MiB";
|
||||
static char constexpr MemGStr[] = "GiB";
|
||||
static char constexpr MemTStr[] = "TiB";
|
||||
// --- Config File
|
||||
|
||||
static auto constexpr DiskK = size_t{ 1000 };
|
||||
static char constexpr DiskKStr[] = "kB";
|
||||
static char constexpr DiskMStr[] = "MB";
|
||||
static char constexpr DiskGStr[] = "GB";
|
||||
static char constexpr DiskTStr[] = "TB";
|
||||
|
||||
static auto constexpr SpeedK = size_t{ 1000 };
|
||||
static char constexpr SpeedKStr[] = "kB/s";
|
||||
static char constexpr SpeedMStr[] = "MB/s";
|
||||
static char constexpr SpeedGStr[] = "GB/s";
|
||||
static char constexpr SpeedTStr[] = "TB/s";
|
||||
|
||||
/***
|
||||
**** Config File
|
||||
***/
|
||||
|
||||
static auto constexpr Options = std::array<tr_option, 45>{
|
||||
auto constexpr Options = std::array<tr_option, 45>{
|
||||
{ { 'a', "allowed", "Allowed IP addresses. (Default: " TR_DEFAULT_RPC_WHITELIST ")", "a", true, "<list>" },
|
||||
{ 'b', "blocklist", "Enable peer blocklists", "b", false, nullptr },
|
||||
{ 'B', "no-blocklist", "Disable peer blocklists", "B", false, nullptr },
|
||||
|
@ -162,35 +144,7 @@ static auto constexpr Options = std::array<tr_option, 45>{
|
|||
{ 0, nullptr, nullptr, nullptr, false, nullptr } }
|
||||
};
|
||||
|
||||
bool tr_daemon::reopen_log_file(char const* filename)
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
tr_sys_file_t const old_log_file = logfile_;
|
||||
tr_sys_file_t const new_log_file = tr_sys_file_open(
|
||||
filename,
|
||||
TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_APPEND,
|
||||
0666,
|
||||
&error);
|
||||
|
||||
if (new_log_file == TR_BAD_SYS_FILE)
|
||||
{
|
||||
fprintf(stderr, "Couldn't (re)open log file \"%s\": %s\n", filename, error->message);
|
||||
tr_error_free(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
logfile_ = new_log_file;
|
||||
logfile_flush_ = tr_sys_file_flush_possible(logfile_);
|
||||
|
||||
if (old_log_file != TR_BAD_SYS_FILE)
|
||||
{
|
||||
tr_sys_file_close(old_log_file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string getConfigDir(int argc, char const* const* argv)
|
||||
[[nodiscard]] std::string getConfigDir(int argc, char const* const* argv)
|
||||
{
|
||||
int c;
|
||||
char const* optstr;
|
||||
|
@ -209,7 +163,7 @@ static std::string getConfigDir(int argc, char const* const* argv)
|
|||
return tr_getDefaultConfigDir(MyName);
|
||||
}
|
||||
|
||||
static auto onFileAdded(tr_session const* session, std::string_view dirname, std::string_view basename)
|
||||
auto onFileAdded(tr_session* session, std::string_view dirname, std::string_view basename)
|
||||
{
|
||||
auto const lowercase = tr_strlower(basename);
|
||||
auto const is_torrent = tr_strv_ends_with(lowercase, ".torrent"sv);
|
||||
|
@ -235,15 +189,14 @@ static auto onFileAdded(tr_session const* session, std::string_view dirname, std
|
|||
else // is_magnet
|
||||
{
|
||||
auto content = std::vector<char>{};
|
||||
tr_error* error = nullptr;
|
||||
auto error = tr_error{};
|
||||
if (!tr_file_read(filename, content, &error))
|
||||
{
|
||||
tr_logAddWarn(fmt::format(
|
||||
_("Couldn't read '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", basename),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code)));
|
||||
tr_error_free(error);
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code())));
|
||||
retry = true;
|
||||
}
|
||||
else
|
||||
|
@ -274,18 +227,15 @@ static auto onFileAdded(tr_session const* session, std::string_view dirname, std
|
|||
|
||||
if (test && trash)
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
|
||||
tr_logAddInfo(fmt::format(_("Removing torrent file '{path}'"), fmt::arg("path", basename)));
|
||||
|
||||
if (!tr_sys_path_remove(filename, &error))
|
||||
if (auto error = tr_error{}; !tr_sys_path_remove(filename, &error))
|
||||
{
|
||||
tr_logAddError(fmt::format(
|
||||
_("Couldn't remove '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", basename),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code)));
|
||||
tr_error_free(error);
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code())));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -298,7 +248,7 @@ static auto onFileAdded(tr_session const* session, std::string_view dirname, std
|
|||
return Watchdir::Action::Done;
|
||||
}
|
||||
|
||||
static char const* levelName(tr_log_level level)
|
||||
[[nodiscard]] constexpr char const* levelName(tr_log_level level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
|
@ -317,7 +267,7 @@ static char const* levelName(tr_log_level level)
|
|||
}
|
||||
}
|
||||
|
||||
static void printMessage(
|
||||
void printMessage(
|
||||
tr_sys_file_t file,
|
||||
tr_log_level level,
|
||||
std::string_view name,
|
||||
|
@ -379,7 +329,7 @@ static void printMessage(
|
|||
#endif
|
||||
}
|
||||
|
||||
static void pumpLogMessages(tr_sys_file_t file, bool flush)
|
||||
void pumpLogMessages(tr_sys_file_t file, bool flush)
|
||||
{
|
||||
tr_log_message* list = tr_logGetQueue();
|
||||
|
||||
|
@ -396,7 +346,62 @@ static void pumpLogMessages(tr_sys_file_t file, bool flush)
|
|||
tr_logFreeQueue(list);
|
||||
}
|
||||
|
||||
void tr_daemon::report_status(void)
|
||||
void periodic_update(evutil_socket_t /*fd*/, short /*what*/, void* arg)
|
||||
{
|
||||
static_cast<tr_daemon*>(arg)->periodic_update();
|
||||
}
|
||||
|
||||
tr_rpc_callback_status on_rpc_callback(tr_session* /*session*/, tr_rpc_callback_type type, tr_torrent* /*tor*/, void* arg)
|
||||
{
|
||||
if (type == TR_RPC_SESSION_CLOSE)
|
||||
{
|
||||
static_cast<tr_daemon*>(arg)->stop();
|
||||
}
|
||||
return TR_RPC_OK;
|
||||
}
|
||||
|
||||
tr_variant load_settings(char const* config_dir)
|
||||
{
|
||||
auto app_defaults = tr_variant::make_map();
|
||||
tr_variantDictAddBool(&app_defaults, TR_KEY_rpc_enabled, true);
|
||||
return tr_sessionLoadSettings(&app_defaults, config_dir, MyName);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool tr_daemon::reopen_log_file(char const* filename)
|
||||
{
|
||||
auto error = tr_error{};
|
||||
tr_sys_file_t const old_log_file = logfile_;
|
||||
tr_sys_file_t const new_log_file = tr_sys_file_open(
|
||||
filename,
|
||||
TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_APPEND,
|
||||
0666,
|
||||
&error);
|
||||
|
||||
if (new_log_file == TR_BAD_SYS_FILE)
|
||||
{
|
||||
auto const errmsg = fmt::format(
|
||||
"Couldn't open '{path}': {error} ({error_code})",
|
||||
fmt::arg("path", filename),
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code()));
|
||||
fmt::print(stderr, "{:s}\n", errmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
logfile_ = new_log_file;
|
||||
logfile_flush_ = tr_sys_file_flush_possible(logfile_);
|
||||
|
||||
if (old_log_file != TR_BAD_SYS_FILE)
|
||||
{
|
||||
tr_sys_file_close(old_log_file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tr_daemon::report_status()
|
||||
{
|
||||
double const up = tr_sessionGetRawSpeed_KBps(my_session_, TR_UP);
|
||||
double const dn = tr_sessionGetRawSpeed_KBps(my_session_, TR_DOWN);
|
||||
|
@ -411,30 +416,12 @@ void tr_daemon::report_status(void)
|
|||
}
|
||||
}
|
||||
|
||||
void tr_daemon::periodic_update(void)
|
||||
void tr_daemon::periodic_update()
|
||||
{
|
||||
pumpLogMessages(logfile_, logfile_flush_);
|
||||
report_status();
|
||||
}
|
||||
|
||||
static void periodic_update(evutil_socket_t /*fd*/, short /*what*/, void* arg)
|
||||
{
|
||||
static_cast<tr_daemon*>(arg)->periodic_update();
|
||||
}
|
||||
|
||||
static tr_rpc_callback_status on_rpc_callback(
|
||||
tr_session* /*session*/,
|
||||
tr_rpc_callback_type type,
|
||||
tr_torrent* /*tor*/,
|
||||
void* arg)
|
||||
{
|
||||
if (type == TR_RPC_SESSION_CLOSE)
|
||||
{
|
||||
static_cast<tr_daemon*>(arg)->stop();
|
||||
}
|
||||
return TR_RPC_OK;
|
||||
}
|
||||
|
||||
bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_settings, bool* foreground, int* exit_code)
|
||||
{
|
||||
int c;
|
||||
|
@ -518,7 +505,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting
|
|||
break;
|
||||
|
||||
case 'p':
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_rpc_port, atoi(optstr));
|
||||
if (auto const rpc_port = tr_num_parse<uint16_t>(optstr); rpc_port)
|
||||
{
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_rpc_port, *rpc_port);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
|
@ -542,7 +532,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting
|
|||
break;
|
||||
|
||||
case 'P':
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_port, atoi(optstr));
|
||||
if (auto const peer_port = tr_num_parse<uint16_t>(optstr); peer_port)
|
||||
{
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_port, *peer_port);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
|
@ -554,11 +547,17 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting
|
|||
break;
|
||||
|
||||
case 'L':
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_global, atoi(optstr));
|
||||
if (auto const peer_limit_global = tr_num_parse<int64_t>(optstr); peer_limit_global && *peer_limit_global >= 0)
|
||||
{
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_global, *peer_limit_global);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_per_torrent, atoi(optstr));
|
||||
if (auto const peer_limit_tor = tr_num_parse<int64_t>(optstr); peer_limit_tor && *peer_limit_tor >= 0)
|
||||
{
|
||||
tr_variantDictAddInt(&settings_, TR_KEY_peer_limit_per_torrent, *peer_limit_tor);
|
||||
}
|
||||
break;
|
||||
|
||||
case 800:
|
||||
|
@ -590,7 +589,10 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting
|
|||
break;
|
||||
|
||||
case 953:
|
||||
tr_variantDictAddReal(&settings_, TR_KEY_ratio_limit, atof(optstr));
|
||||
if (auto const ratio_limit = tr_num_parse<double>(optstr); optstr)
|
||||
{
|
||||
tr_variantDictAddReal(&settings_, TR_KEY_ratio_limit, *ratio_limit);
|
||||
}
|
||||
tr_variantDictAddBool(&settings_, TR_KEY_ratio_limit_enabled, true);
|
||||
break;
|
||||
|
||||
|
@ -660,7 +662,7 @@ bool tr_daemon::parse_args(int argc, char const* const* argv, bool* dump_setting
|
|||
return true;
|
||||
}
|
||||
|
||||
void tr_daemon::reconfigure(void)
|
||||
void tr_daemon::reconfigure()
|
||||
{
|
||||
if (my_session_ == nullptr)
|
||||
{
|
||||
|
@ -680,35 +682,24 @@ void tr_daemon::reconfigure(void)
|
|||
configDir = tr_sessionGetConfigDir(my_session_);
|
||||
tr_logAddInfo(fmt::format(_("Reloading settings from '{path}'"), fmt::arg("path", configDir)));
|
||||
|
||||
auto newsettings = tr_variant::make_map();
|
||||
tr_variantDictAddBool(&newsettings, TR_KEY_rpc_enabled, true);
|
||||
newsettings.merge(tr_sessionLoadSettings(configDir, MyName));
|
||||
|
||||
tr_sessionSet(my_session_, newsettings);
|
||||
tr_sessionSet(my_session_, load_settings(configDir));
|
||||
tr_sessionReloadBlocklists(my_session_);
|
||||
}
|
||||
}
|
||||
|
||||
void tr_daemon::stop(void)
|
||||
void tr_daemon::stop()
|
||||
{
|
||||
event_base_loopexit(ev_base_, nullptr);
|
||||
}
|
||||
|
||||
int tr_daemon::start([[maybe_unused]] bool foreground)
|
||||
{
|
||||
bool boolVal;
|
||||
bool pidfile_created = false;
|
||||
tr_session* session = nullptr;
|
||||
struct event* status_ev = nullptr;
|
||||
struct event* sig_ev = nullptr;
|
||||
auto watchdir = std::unique_ptr<Watchdir>{};
|
||||
char const* const cdir = this->config_dir_.c_str();
|
||||
|
||||
sd_notifyf(0, "MAINPID=%d\n", (int)getpid());
|
||||
|
||||
/* setup event state */
|
||||
ev_base_ = event_base_new();
|
||||
|
||||
event* sig_ev = nullptr;
|
||||
if (ev_base_ == nullptr || !setup_signals(sig_ev))
|
||||
{
|
||||
auto const error_code = errno;
|
||||
|
@ -722,10 +713,8 @@ int tr_daemon::start([[maybe_unused]] bool foreground)
|
|||
}
|
||||
|
||||
/* start the session */
|
||||
tr_formatter_mem_init(MemK, MemKStr, MemMStr, MemGStr, MemTStr);
|
||||
tr_formatter_size_init(DiskK, DiskKStr, DiskMStr, DiskGStr, DiskTStr);
|
||||
tr_formatter_speed_init(SpeedK, SpeedKStr, SpeedMStr, SpeedGStr, SpeedTStr);
|
||||
session = tr_sessionInit(cdir, true, settings_);
|
||||
auto const* const cdir = this->config_dir_.c_str();
|
||||
auto* session = tr_sessionInit(cdir, true, settings_);
|
||||
tr_sessionSetRPCCallback(session, on_rpc_callback, this);
|
||||
tr_logAddInfo(fmt::format(_("Loading settings from '{path}'"), fmt::arg("path", cdir)));
|
||||
tr_sessionSaveSettings(session, cdir, settings_);
|
||||
|
@ -733,9 +722,10 @@ int tr_daemon::start([[maybe_unused]] bool foreground)
|
|||
auto sv = std::string_view{};
|
||||
(void)tr_variantDictFindStrView(&settings_, key_pidfile_, &sv);
|
||||
auto const sz_pid_filename = std::string{ sv };
|
||||
auto pidfile_created = false;
|
||||
if (!std::empty(sz_pid_filename))
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
auto error = tr_error{};
|
||||
tr_sys_file_t fp = tr_sys_file_open(
|
||||
sz_pid_filename.c_str(),
|
||||
TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE,
|
||||
|
@ -755,13 +745,12 @@ int tr_daemon::start([[maybe_unused]] bool foreground)
|
|||
tr_logAddError(fmt::format(
|
||||
_("Couldn't save '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", sz_pid_filename),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code)));
|
||||
tr_error_free(error);
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code())));
|
||||
}
|
||||
}
|
||||
|
||||
if (tr_variantDictFindBool(&settings_, TR_KEY_rpc_authentication_required, &boolVal) && boolVal)
|
||||
if (auto tmp_bool = false; tr_variantDictFindBool(&settings_, TR_KEY_rpc_authentication_required, &tmp_bool) && tmp_bool)
|
||||
{
|
||||
tr_logAddInfo(_("Requiring authentication"));
|
||||
}
|
||||
|
@ -775,7 +764,8 @@ int tr_daemon::start([[maybe_unused]] bool foreground)
|
|||
}
|
||||
|
||||
/* maybe add a watchdir */
|
||||
if (tr_variantDictFindBool(&settings_, TR_KEY_watch_dir_enabled, &boolVal) && boolVal)
|
||||
auto watchdir = std::unique_ptr<Watchdir>{};
|
||||
if (auto tmp_bool = false; tr_variantDictFindBool(&settings_, TR_KEY_watch_dir_enabled, &tmp_bool) && tmp_bool)
|
||||
{
|
||||
auto force_generic = bool{ false };
|
||||
(void)tr_variantDictFindBool(&settings_, key_watch_dir_force_generic_, &force_generic);
|
||||
|
@ -820,6 +810,7 @@ int tr_daemon::start([[maybe_unused]] bool foreground)
|
|||
#endif
|
||||
|
||||
/* Create new timer event to report daemon status */
|
||||
event* status_ev;
|
||||
{
|
||||
constexpr auto one_sec = timeval{ 1, 0 }; // 1 second
|
||||
status_ev = event_new(ev_base_, -1, EV_PERSIST, &::periodic_update, this);
|
||||
|
@ -906,9 +897,7 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int*
|
|||
config_dir_ = getConfigDir(argc, argv);
|
||||
|
||||
/* load settings from defaults + config file */
|
||||
settings_ = tr_variant::make_map();
|
||||
tr_variantDictAddBool(&settings_, TR_KEY_rpc_enabled, true);
|
||||
settings_.merge(tr_sessionLoadSettings(config_dir_.c_str(), MyName));
|
||||
settings_ = load_settings(config_dir_.c_str());
|
||||
|
||||
bool dumpSettings;
|
||||
|
||||
|
@ -917,7 +906,7 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int*
|
|||
/* overwrite settings from the command line */
|
||||
if (!parse_args(argc, argv, &dumpSettings, foreground, ret))
|
||||
{
|
||||
goto EXIT_EARLY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*foreground && logfile_ == TR_BAD_SYS_FILE)
|
||||
|
@ -929,20 +918,16 @@ bool tr_daemon::init(int argc, char const* const argv[], bool* foreground, int*
|
|||
if (dumpSettings)
|
||||
{
|
||||
fmt::print("{:s}\n", tr_variant_serde::json().to_string(settings_));
|
||||
goto EXIT_EARLY;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
EXIT_EARLY:
|
||||
return false;
|
||||
}
|
||||
|
||||
void tr_daemon::handle_error(tr_error* error) const
|
||||
void tr_daemon::handle_error(tr_error const& error) const
|
||||
{
|
||||
auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code);
|
||||
auto const errmsg = fmt::format("Couldn't daemonize: {:s} ({:d})", error.message(), error.code());
|
||||
printMessage(logfile_, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
|
||||
tr_error_free(error);
|
||||
}
|
||||
|
||||
int tr_main(int argc, char* argv[])
|
||||
|
@ -951,16 +936,15 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
tr_locale_set_global("");
|
||||
|
||||
int ret;
|
||||
tr_daemon daemon;
|
||||
bool foreground;
|
||||
tr_error* error = nullptr;
|
||||
|
||||
auto foreground = bool{};
|
||||
auto ret = int{};
|
||||
auto daemon = tr_daemon{};
|
||||
if (!daemon.init(argc, argv, &foreground, &ret))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
if (!daemon.spawn(foreground, &ret, &error))
|
||||
|
||||
if (auto error = tr_error{}; !daemon.spawn(foreground, &ret, error))
|
||||
{
|
||||
daemon.handle_error(error);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2015-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -33,9 +33,9 @@ public:
|
|||
#endif /* signalfd API */
|
||||
}
|
||||
|
||||
bool spawn(bool foreground, int* exit_code, tr_error** error);
|
||||
bool spawn(bool foreground, int* exit_code, tr_error& error);
|
||||
bool init(int argc, char const* const argv[], bool* foreground, int* ret);
|
||||
void handle_error(tr_error*) const;
|
||||
void handle_error(tr_error const&) const;
|
||||
int start(bool foreground);
|
||||
void periodic_update();
|
||||
void reconfigure();
|
||||
|
|
|
@ -127,12 +127,14 @@ Disable uTP for peer connections.
|
|||
Where to store downloaded data.
|
||||
.It Fl e Fl -logfile
|
||||
Where to store transmission's log messages.
|
||||
.It Fl -log-level Ar level
|
||||
Log level. Must be 'critical', 'error', 'warn', 'info', 'debug', or 'trace'.
|
||||
.It Fl -log-error
|
||||
Show error messages
|
||||
Deprecated. Use --log-level=error
|
||||
.It Fl -log-info
|
||||
Show error and info messages
|
||||
Deprecated. Use --log-level=info
|
||||
.It Fl -log-debug
|
||||
Show error, info, and debug messages
|
||||
Deprecated. Use --log-level=debug
|
||||
.It Fl x Fl -pid-file
|
||||
Name of PID file
|
||||
.El
|
||||
|
|
|
@ -8,10 +8,31 @@ User=transmission
|
|||
Type=notify
|
||||
ExecStart=/usr/bin/transmission-daemon -f --log-level=error
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet=
|
||||
DevicePolicy=closed
|
||||
KeyringMode=private
|
||||
LockPersonality=true
|
||||
NoNewPrivileges=true
|
||||
MemoryDenyWriteExecute=true
|
||||
ProtectSystem=true
|
||||
PrivateTmp=true
|
||||
PrivateDevices=true
|
||||
ProtectClock=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
ProtectKernelModules=true
|
||||
ProtectSystem=true
|
||||
ProtectHostname=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectProc=invisible
|
||||
RestrictNamespaces=true
|
||||
RestrictSUIDSGID=true
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictRealtime=true
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallArchitectures=native
|
||||
SystemCallErrorNumber=EPERM
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -58,7 +58,7 @@ else()
|
|||
endif()
|
||||
|
||||
file(
|
||||
COPY "${CMAKE_SOURCE_DIR}/qt/icons/transmission.ico"
|
||||
COPY "${PROJECT_SOURCE_DIR}/qt/icons/transmission.ico"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(WEBSRCDIR "${CMAKE_INSTALL_PREFIX}/share/transmission/public_html")
|
||||
|
|
|
@ -19,41 +19,41 @@ Transmission has an Xcode project file for building in Xcode.
|
|||
- Open Transmission.xcodeproj
|
||||
- Run the Transmission scheme
|
||||
|
||||
### Building the native app with ninja ###
|
||||
### Building the native app with CMake ###
|
||||
Build the app:
|
||||
```console
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
ninja -C build transmission-mac
|
||||
cmake --build build -t transmission-mac
|
||||
open ./build/macosx/Transmission.app
|
||||
```
|
||||
|
||||
### Building the GTK app with ninja ###
|
||||
### Building the GTK app with CMake ###
|
||||
Install GTK and build the app:
|
||||
```console
|
||||
brew install gtk4 gtkmm4
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_GTK=ON -DENABLE_MAC=OFF
|
||||
ninja -C build transmission-gtk
|
||||
cmake --build build -t transmission-gtk
|
||||
./build/gtk/transmission-gtk
|
||||
```
|
||||
|
||||
## On Unix ##
|
||||
### Prerequisites ###
|
||||
|
||||
#### Debian 11 / Bullseye ####
|
||||
#### Debian 11 and Newer ####
|
||||
On Debian, you can build transmission with a few dependencies on top of a base installation.
|
||||
|
||||
For building transmission-daemon you will need basic dependencies
|
||||
```console
|
||||
```bash
|
||||
$ sudo apt install git build-essential cmake libcurl4-openssl-dev libssl-dev python3
|
||||
```
|
||||
You likely want to install transmission as a native GUI application. There are two options, GTK and QT.
|
||||
|
||||
For GTK 3 client, two additional packages are required
|
||||
```console
|
||||
```bash
|
||||
$ sudo apt install libgtkmm-3.0-dev gettext
|
||||
```
|
||||
For QT client, one additional package is needed on top of basic dependencies
|
||||
```console
|
||||
```bash
|
||||
$ sudo apt install qttools5-dev
|
||||
```
|
||||
|
||||
|
@ -62,7 +62,7 @@ Then you can begin [building.](#building-transmission-from-git-first-time)
|
|||
#### Ubuntu ####
|
||||
On Ubuntu, you can install the required development tools for GTK with this command:
|
||||
|
||||
```console
|
||||
```bash
|
||||
$ sudo apt-get install build-essential automake autoconf libtool pkg-config intltool libcurl4-openssl-dev libglib2.0-dev libevent-dev libminiupnpc-dev libgtk-3-dev libappindicator3-dev libssl-dev
|
||||
```
|
||||
|
||||
|
@ -80,7 +80,7 @@ The packages you need are:
|
|||
* openssl-devel
|
||||
|
||||
Or simply run the following command:
|
||||
```console
|
||||
```bash
|
||||
$ yum install gcc gcc-c++ m4 make automake libtool gettext openssl-devel
|
||||
```
|
||||
|
||||
|
@ -90,33 +90,31 @@ However, Transmission needs other packages unavailable in `yum`:
|
|||
* [intltool](https://ftp.gnome.org/pub/gnome/sources/intltool/)
|
||||
|
||||
Before building Transmission, you need to set the pkgconfig environment setting:
|
||||
```console
|
||||
```bash
|
||||
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
|
||||
```
|
||||
|
||||
### Building Transmission from Git (first time) ###
|
||||
```console
|
||||
$ git clone https://github.com/transmission/transmission Transmission
|
||||
```bash
|
||||
$ git clone --recurse-submodules https://github.com/transmission/transmission Transmission
|
||||
$ cd Transmission
|
||||
$ git submodule update --init --recursive
|
||||
$ mkdir build
|
||||
# Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary with debug information. (preferred)
|
||||
# Use -DCMAKE_BUILD_TYPE=Release to build full optimized binary.
|
||||
$ cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
$ cd build
|
||||
$ # Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary.
|
||||
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
$ cmake --build .
|
||||
$ sudo cmake --install .
|
||||
```
|
||||
|
||||
### Building Transmission from Git (updating) ###
|
||||
```console
|
||||
```bash
|
||||
$ cd Transmission/build
|
||||
$ make clean
|
||||
$ cmake --build . -t clean
|
||||
$ git submodule foreach --recursive git clean -xfd
|
||||
$ git pull --rebase --prune
|
||||
$ git submodule update --recursive
|
||||
$ # Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary.
|
||||
$ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
$ make
|
||||
$ sudo make install
|
||||
$ git submodule update --init --recursive
|
||||
$ cmake --build .
|
||||
$ sudo cmake --install .
|
||||
```
|
||||
|
||||
## On Windows ##
|
||||
|
@ -138,17 +136,17 @@ You need the following installed:
|
|||
Vcpkg will install x86 libraries by default. To install x64 add the `--triplet=x64-windows` flag at the end of the commands below.
|
||||
|
||||
Common dependencies:
|
||||
```
|
||||
```bat
|
||||
vcpkg install curl zlib openssl
|
||||
```
|
||||
|
||||
Additional dependencies for the Qt client:
|
||||
```
|
||||
```bat
|
||||
vcpkg install qt5-tools qt5-winextras
|
||||
```
|
||||
|
||||
### Get Transmission source
|
||||
```
|
||||
```bat
|
||||
git clone https://github.com/transmission/transmission
|
||||
cd transmission
|
||||
git submodule update --init --recursive
|
||||
|
@ -163,11 +161,11 @@ Each option can be set to `ON` or `OFF`, values shown below are the defaults.
|
|||
* `-DENABLE_UTILS=ON` - build transmission-remote, transmission-create, transmission-edit and transmission-show cli tools
|
||||
* `-DENABLE_CLI=OFF` - build the cli client
|
||||
|
||||
```
|
||||
```bat
|
||||
cmake -B build -DCMAKE_TOOLCHAIN_FILE="<path-to-vcpkg>\scripts\buildsystems\vcpkg.cmake" <flags-from-above> <other-cmake-configurations>
|
||||
```
|
||||
|
||||
To build the project run:
|
||||
```
|
||||
```bat
|
||||
cmake --build build
|
||||
```
|
||||
|
|
|
@ -81,7 +81,6 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri
|
|||
* **message-level:** Number (0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace; default = 2) Set verbosity of Transmission's log messages.
|
||||
* **pex-enabled:** Boolean (default = true) Enable [Peer Exchange (PEX)](https://en.wikipedia.org/wiki/Peer_exchange).
|
||||
* **pidfile:** String Path to file in which daemon PID will be stored (transmission-daemon only)
|
||||
* **prefetch-enabled:** Boolean (default = true). When enabled, Transmission will hint to the OS which piece data it's about to read from disk in order to satisfy requests from peers. On Linux, this is done by passing `POSIX_FADV_WILLNEED` to [posix_fadvise()](https://www.kernel.org/doc/man-pages/online/pages/man2/posix_fadvise.2.html). On macOS, this is done by passing `F_RDADVISE` to [fcntl()](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html).
|
||||
* **scrape-paused-torrents-enabled:** Boolean (default = true)
|
||||
* **script-torrent-added-enabled:** Boolean (default = false) Run a script when a torrent is added to Transmission. Environmental variables are passed in as detailed on the [Scripts](./Scripts.md) page
|
||||
* **script-torrent-added-filename:** String (default = "") Path to script.
|
||||
|
|
|
@ -1,15 +1,38 @@
|
|||
## Peer-ID
|
||||
From version 0.80 onward, Transmission's peer-id is formatted in Azureus' style with one digit for the major version, two digits for the minor version and one character to denote a stable release (`0`), nightly build (`Z`) or prerelease beta (`X`). For example:
|
||||
* `-TR1330-` — Official 1.33 release
|
||||
* `-TR133Z-` — Nightly build between 1.33 and 1.34
|
||||
* `-TR133X-` — Beta release of 1.34
|
||||
|
||||
Rationale: This differentiates between official and unofficial releases in a way which is easy for trackers to detect with simple string comparison. An official release (`-TR1330-`) is lexicographically smaller than its post-release unsupported versions (`-TR133Z-` and `-TR133X-`), which in turn are lexicographically smaller than the next official release (`-TR1340-`).
|
||||
Transmission's peer-ids follow Azureus' style with code `TR`. Peer-id prefix is `-TR????-`, where `????` are four bytes encoding the client's version. Client version encoding changed over the client's history.
|
||||
|
||||
Before 0.80, versions of Transmission used two digits for the major version and two for the minor version. For example, `-TR0072-` was Transmission 0.72.
|
||||
### Current scheme
|
||||
|
||||
Starting from version 3.00, peer-ids are formatted `-TRXYZR-` where `X`, `Y`, `Z` are [base62](https://en.wikipedia.org/wiki/Base62) major, minor, patch version numbers, and `R` is one of `0` (stable release), `B` (beta release), or `Z` (dev build). For example:
|
||||
|
||||
* `-TR40aZ-` — 4.0.36 Dev
|
||||
* `-TR400B-` — 4.0.0 Beta
|
||||
* `-TR4A00-` — 4.11.0
|
||||
|
||||
The suffix scheme was changed after 3.00 for consistency with other clients.
|
||||
|
||||
### 0.80 up to 3.00
|
||||
|
||||
From version 0.80 up to 3.00, Transmission's peer-ids were formatted `-TRXYYR-`, where `X` was one base10 digit for the major version and `YY` were two base10 digits for the minor version. `R` was a suffix denoting a stable release (`0`), nightly build (`Z`), or prerelease beta (`X`). For example:
|
||||
|
||||
* `-TR133Z-` — Nightly build between 1.33 and 1.34
|
||||
* `-TR133X-` — 1.34 Beta
|
||||
* `-TR1330-` — 1.33
|
||||
|
||||
Rationale at the time: this differentiates between official and unofficial releases in a way which is easy for trackers to detect with simple string comparison. An official release (`-TR1330-`) is lexicographically smaller than its post-release unsupported versions (`-TR133Z-` and `-TR133X-`), which in turn are lexicographically smaller than the next official release (`-TR1340-`).
|
||||
|
||||
### Before 0.80
|
||||
|
||||
Before 0.80, Transmission used two base10 digits for the major version and two base10 digits for the minor version. For example:
|
||||
|
||||
* `-TR0072-` — 0.72
|
||||
* `-TR0006-` — 0.6
|
||||
|
||||
## User-Agent
|
||||
|
||||
Its User-Agent header follows a similar format, plus the VCS revision in parentheses:
|
||||
|
||||
* Transmission/1.30X (6416) — Beta release leading up to version 1.30
|
||||
* Transmission/1.32 (6455) — Official 1.32 release
|
||||
* Transmission/1.32+ (6499) — Nightly build between 1.32 and 1.33
|
||||
|
|
|
@ -31,6 +31,7 @@ Much of this documentation is out-of-date or could be improved. Pull requests ar
|
|||
* [RPC protocol specification](rpc-spec.md)
|
||||
* [Transmission's Peer ID and User-Agent headers](Peer-ID-and-User-Agent.md)
|
||||
* [Peer status text explained](Peer-Status-Text.md)
|
||||
* [Securing Transmission's RPC interface with an open-source reverse proxy (External Link)](https://www.pomerium.com/docs/guides/transmission)
|
||||
|
||||
# 3. Report a problem / request a feature #
|
||||
* [Check](https://github.com/transmission/transmission/issues) whether the problem has already been reported.
|
||||
|
|
|
@ -39,8 +39,6 @@ Functionality of these scripts has been implemented in libtransmission and is th
|
|||
## contrib/scripts
|
||||
Tomas Carnecky (aka wereHamster) is maintaining a set of scripts in his [GitHub repository](https://github.com/wereHamster/transmission/tree/master/contrib/scripts/ ).
|
||||
|
||||
Falk Husemann (aka hxgn) is maintaining scripts in his [blog](https://falkhusemann.de/category/tcp_ip/transmission-tcp_ip/).
|
||||
|
||||
Oguz wrote [on his blog](https://oguzarduc.blogspot.com/2012/05/transmission-quit-script-in-php.html) a PHP script to stop Transmission after it finishes downloading and seeding.
|
||||
Scripts which have not yet been ported and may not work with the latest version:
|
||||
* https://pastebin.com/QzVxQDtM: Bash - (cron)script to keep a maximum number of torrents running; starting and pausing torrents as necessary
|
||||
|
|
|
@ -37,6 +37,8 @@ The file contains the following **per-torrent** properties:
|
|||
<tr><td><tt>bitfield</tt></td><td></td></tr>
|
||||
</table>
|
||||
|
||||
The file format is bencoding, as described in [bep_0003](https://www.bittorrent.org/beps/bep_0003.html).
|
||||
|
||||
## Constants
|
||||
<table>
|
||||
<tr><td>Maximum number of remembered peers</td><td><tt>MAX_REMEMBERED_PEERS</tt></td><td>200</td></tr>
|
||||
|
|
|
@ -112,13 +112,13 @@ username and password (respectively), separated by a colon.
|
|||
|
||||
## 3 Torrent requests
|
||||
### 3.1 Torrent action requests
|
||||
| Method name | libtransmission function
|
||||
|:--|:--
|
||||
| `torrent-start` | tr_torrentStart
|
||||
| `torrent-start-now` | tr_torrentStartNow
|
||||
| `torrent-stop` | tr_torrentStop
|
||||
| `torrent-verify` | tr_torrentVerify
|
||||
| `torrent-reannounce` | tr_torrentManualUpdate ("ask tracker for more peers")
|
||||
| Method name | libtransmission function | Description
|
||||
|:--|:--|:--
|
||||
| `torrent-start` | tr_torrentStart | start torrent
|
||||
| `torrent-start-now` | tr_torrentStartNow | start torrent disregarding queue position
|
||||
| `torrent-stop` | tr_torrentStop | stop torrent
|
||||
| `torrent-verify` | tr_torrentVerify | verify torrent
|
||||
| `torrent-reannounce` | tr_torrentManualUpdate | re-announce to trackers now
|
||||
|
||||
Request arguments: `ids`, which specifies which torrents to use.
|
||||
All torrents are used if the `ids` argument is omitted.
|
||||
|
@ -259,8 +259,8 @@ The 'source' column here corresponds to the data structure there.
|
|||
| `priorities`| array (see below)| n/a
|
||||
| `primary-mime-type`| string| tr_torrent
|
||||
| `queuePosition`| number| tr_stat
|
||||
| `rateDownload (B/s)`| number| tr_stat
|
||||
| `rateUpload (B/s)`| number| tr_stat
|
||||
| `rateDownload` (B/s)| number| tr_stat
|
||||
| `rateUpload` (B/s)| number| tr_stat
|
||||
| `recheckProgress`| double| tr_stat
|
||||
| `secondsDownloading`| number| tr_stat
|
||||
| `secondsSeeding`| number| tr_stat
|
||||
|
@ -642,11 +642,11 @@ A stats object contains:
|
|||
|
||||
| Key | Value Type | transmission.h source
|
||||
|:--|:--|:--
|
||||
| uploadedBytes | number | tr_session_stats
|
||||
| downloadedBytes | number | tr_session_stats
|
||||
| filesAdded | number | tr_session_stats
|
||||
| sessionCount | number | tr_session_stats
|
||||
| secondsActive | number | tr_session_stats
|
||||
| `uploadedBytes` | number | tr_session_stats
|
||||
| `downloadedBytes` | number | tr_session_stats
|
||||
| `filesAdded` | number | tr_session_stats
|
||||
| `sessionCount` | number | tr_session_stats
|
||||
| `secondsActive` | number | tr_session_stats
|
||||
|
||||
### 4.3 Blocklist
|
||||
Method name: `blocklist-update`
|
||||
|
@ -661,9 +661,19 @@ from the outside world.
|
|||
|
||||
Method name: `port-test`
|
||||
|
||||
Request arguments: none
|
||||
Request arguments: an optional argument `ipProtocol`.
|
||||
`ipProtocol` is a string specifying the IP protocol version to be used for the port test.
|
||||
Set to `ipv4` to check IPv4, or set to `ipv6` to check IPv6.
|
||||
For backwards compatibility, it is allowed to omit this argument to get the behaviour before Transmission `4.1.0`,
|
||||
which is to check whichever IP protocol the OS happened to use to connect to our port test service,
|
||||
frankly not very useful.
|
||||
|
||||
Response arguments: a Boolean, `port-is-open`
|
||||
Response arguments:
|
||||
|
||||
| Key | Value Type | Description
|
||||
| :-- | :-- | :--
|
||||
| `port-is-open` | boolean | true if port is open, false if port is closed
|
||||
| `ipProtocol` | string | `ipv4` if the test was carried out on IPv4, `ipv6` if the test was carried out on IPv6, unset if an error occured
|
||||
|
||||
### 4.5 Session shutdown
|
||||
This method tells the transmission session to shut down.
|
||||
|
@ -1014,3 +1024,4 @@ Transmission 4.1.0 (`rpc-version-semver` 5.4.0, `rpc-version`: 18)
|
|||
| `torrent-set` | new arg `sequentialDownload`
|
||||
| `torrent-get` | new arg `files.beginPiece`
|
||||
| `torrent-get` | new arg `files.endPiece`
|
||||
| `port-test` | new arg `ipProtocol`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -11,6 +11,7 @@
|
|||
#include "Utils.h"
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/quark.h>
|
||||
|
||||
#include <giomm/liststore.h>
|
||||
#include <giomm/menuattributeiter.h>
|
||||
|
@ -19,18 +20,22 @@
|
|||
#include <glibmm/i18n.h>
|
||||
#include <glibmm/variant.h>
|
||||
|
||||
#if GTKMM_CHECK_VERSION(4, 0, 0)
|
||||
#include <gtkmm/shortcut.h>
|
||||
#include <gtkmm/shortcutaction.h>
|
||||
#include <gtkmm/shortcuttrigger.h>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#if GTKMM_CHECK_VERSION(4, 0, 0)
|
||||
#include <giomm/liststore.h>
|
||||
#include <gtkmm/shortcut.h>
|
||||
#include <gtkmm/shortcutaction.h>
|
||||
#include <gtkmm/shortcuttrigger.h>
|
||||
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
using VariantString = Glib::Variant<Glib::ustring>;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/log.h>
|
||||
#include <libtransmission/quark.h>
|
||||
#include <libtransmission/rpcimpl.h>
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/version.h>
|
||||
|
@ -100,7 +101,7 @@ namespace
|
|||
auto const AppIconName = "transmission"sv; // TODO(C++20): Use ""s
|
||||
|
||||
char const* const LICENSE =
|
||||
"Copyright 2005-2023. All code is copyrighted by the respective authors.\n"
|
||||
"Copyright 2005-2024. All code is copyrighted by the respective authors.\n"
|
||||
"\n"
|
||||
"Transmission can be redistributed and/or modified under the terms of the "
|
||||
"GNU GPL, versions 2 or 3, or by any future license endorsed by Mnemosyne LLC."
|
||||
|
@ -1012,7 +1013,7 @@ void Application::Impl::on_app_exit()
|
|||
p->attach(*icon, 0, 0, 1, 2);
|
||||
|
||||
auto* top_label = Gtk::make_managed<Gtk::Label>();
|
||||
top_label->set_markup(fmt::format(FMT_STRING("<b>{:s}</b>"), _("Closing Connections…")));
|
||||
top_label->set_markup(fmt::format("<b>{:s}</b>", _("Closing Connections…")));
|
||||
top_label->set_halign(TR_GTK_ALIGN(START));
|
||||
top_label->set_valign(TR_GTK_ALIGN(CENTER));
|
||||
p->attach(*top_label, 1, 0, 1, 1);
|
||||
|
@ -1450,7 +1451,7 @@ bool Application::Impl::call_rpc_for_selected_torrents(std::string const& method
|
|||
|
||||
if (tr_variantListSize(ids) != 0)
|
||||
{
|
||||
tr_rpc_request_exec_json(session, &top, nullptr, nullptr);
|
||||
tr_rpc_request_exec(session, top, {});
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
|
@ -1472,7 +1473,7 @@ void Application::Impl::start_all_torrents()
|
|||
|
||||
tr_variantInitDict(&request, 1);
|
||||
tr_variantDictAddStrView(&request, TR_KEY_method, "torrent-start"sv);
|
||||
tr_rpc_request_exec_json(session, &request, nullptr, nullptr);
|
||||
tr_rpc_request_exec(session, request, {});
|
||||
}
|
||||
|
||||
void Application::Impl::pause_all_torrents()
|
||||
|
@ -1482,7 +1483,7 @@ void Application::Impl::pause_all_torrents()
|
|||
|
||||
tr_variantInitDict(&request, 1);
|
||||
tr_variantDictAddStrView(&request, TR_KEY_method, "torrent-stop"sv);
|
||||
tr_rpc_request_exec_json(session, &request, nullptr, nullptr);
|
||||
tr_rpc_request_exec(session, request, {});
|
||||
}
|
||||
|
||||
void Application::Impl::copy_magnet_link_to_clipboard(Glib::RefPtr<Torrent> const& torrent) const
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -14,7 +14,7 @@
|
|||
#include "Session.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/values.h>
|
||||
#include <libtransmission/web-utils.h>
|
||||
|
||||
#include <gdkmm/pixbuf.h>
|
||||
|
@ -53,6 +53,7 @@
|
|||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdlib> // abort()
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
@ -71,6 +72,8 @@
|
|||
|
||||
using namespace std::literals;
|
||||
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
class DetailsDialog::Impl
|
||||
{
|
||||
public:
|
||||
|
@ -444,7 +447,7 @@ void DetailsDialog::Impl::torrent_set_bool(tr_quark key, bool value)
|
|||
tr_variantListAddInt(ids, id);
|
||||
}
|
||||
|
||||
core_->exec(&top);
|
||||
core_->exec(top);
|
||||
}
|
||||
|
||||
void DetailsDialog::Impl::torrent_set_int(tr_quark key, int value)
|
||||
|
@ -462,7 +465,7 @@ void DetailsDialog::Impl::torrent_set_int(tr_quark key, int value)
|
|||
tr_variantListAddInt(ids, id);
|
||||
}
|
||||
|
||||
core_->exec(&top);
|
||||
core_->exec(top);
|
||||
}
|
||||
|
||||
void DetailsDialog::Impl::torrent_set_real(tr_quark key, double value)
|
||||
|
@ -480,15 +483,18 @@ void DetailsDialog::Impl::torrent_set_real(tr_quark key, double value)
|
|||
tr_variantListAddInt(ids, id);
|
||||
}
|
||||
|
||||
core_->exec(&top);
|
||||
core_->exec(top);
|
||||
}
|
||||
|
||||
void DetailsDialog::Impl::options_page_init(Glib::RefPtr<Gtk::Builder> const& /*builder*/)
|
||||
{
|
||||
auto const speed_units_kbyps_str = Speed::units().display_name(Speed::Units::KByps);
|
||||
|
||||
honor_limits_check_tag_ = honor_limits_check_->signal_toggled().connect(
|
||||
[this]() { torrent_set_bool(TR_KEY_honorsSessionLimits, honor_limits_check_->get_active()); });
|
||||
|
||||
down_limited_check_->set_label(fmt::format(down_limited_check_->get_label().raw(), fmt::arg("speed_units", speed_K_str)));
|
||||
down_limited_check_->set_label(
|
||||
fmt::format(fmt::runtime(down_limited_check_->get_label().raw()), fmt::arg("speed_units", speed_units_kbyps_str)));
|
||||
down_limited_check_tag_ = down_limited_check_->signal_toggled().connect(
|
||||
[this]() { torrent_set_bool(TR_KEY_downloadLimited, down_limited_check_->get_active()); });
|
||||
|
||||
|
@ -496,7 +502,8 @@ void DetailsDialog::Impl::options_page_init(Glib::RefPtr<Gtk::Builder> const& /*
|
|||
down_limit_spin_tag_ = down_limit_spin_->signal_value_changed().connect(
|
||||
[this]() { torrent_set_int(TR_KEY_downloadLimit, down_limit_spin_->get_value_as_int()); });
|
||||
|
||||
up_limited_check_->set_label(fmt::format(up_limited_check_->get_label().raw(), fmt::arg("speed_units", speed_K_str)));
|
||||
up_limited_check_->set_label(
|
||||
fmt::format(fmt::runtime(up_limited_check_->get_label().raw()), fmt::arg("speed_units", speed_units_kbyps_str)));
|
||||
up_limited_check_tag_ = up_limited_check_->signal_toggled().connect(
|
||||
[this]() { torrent_set_bool(TR_KEY_uploadLimited, up_limited_check_->get_active()); });
|
||||
|
||||
|
@ -601,12 +608,12 @@ void gtr_text_buffer_set_text(Glib::RefPtr<Gtk::TextBuffer> const& b, Glib::ustr
|
|||
|
||||
[[nodiscard]] std::string get_date_string(time_t t)
|
||||
{
|
||||
return t == 0 ? _("N/A") : fmt::format(FMT_STRING("{:%x}"), fmt::localtime(t));
|
||||
return t == 0 ? _("N/A") : fmt::format("{:%x}", fmt::localtime(t));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string get_date_time_string(time_t t)
|
||||
{
|
||||
return t == 0 ? _("N/A") : fmt::format(FMT_STRING("{:%c}"), fmt::localtime(t));
|
||||
return t == 0 ? _("N/A") : fmt::format("{:%c}", fmt::localtime(t));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -626,7 +633,7 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
|||
infos.reserve(torrents.size());
|
||||
for (auto* const torrent : torrents)
|
||||
{
|
||||
stats.push_back(tr_torrentStatCached(torrent));
|
||||
stats.push_back(tr_torrentStat(torrent));
|
||||
infos.push_back(tr_torrentView(torrent));
|
||||
}
|
||||
|
||||
|
@ -886,7 +893,7 @@ void DetailsDialog::Impl::refreshInfo(std::vector<tr_torrent*> const& torrents)
|
|||
"({piece_count} BitTorrent pieces @ {piece_size})",
|
||||
piece_count),
|
||||
fmt::arg("piece_count", piece_count),
|
||||
fmt::arg("piece_size", tr_formatter_mem_B(piece_size)));
|
||||
fmt::arg("piece_size", Memory{ piece_size, Memory::Units::Bytes }.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,14 +1113,14 @@ public:
|
|||
add(key);
|
||||
add(was_updated);
|
||||
add(url);
|
||||
add(download_rate_double);
|
||||
add(download_rate_speed);
|
||||
add(download_rate_string);
|
||||
}
|
||||
|
||||
Gtk::TreeModelColumn<std::string> key;
|
||||
Gtk::TreeModelColumn<bool> was_updated;
|
||||
Gtk::TreeModelColumn<Glib::ustring> url;
|
||||
Gtk::TreeModelColumn<double> download_rate_double;
|
||||
Gtk::TreeModelColumn<Speed> download_rate_speed;
|
||||
Gtk::TreeModelColumn<Glib::ustring> download_rate_string;
|
||||
};
|
||||
|
||||
|
@ -1128,9 +1135,9 @@ public:
|
|||
add(was_updated);
|
||||
add(address);
|
||||
add(address_collated);
|
||||
add(download_rate_double);
|
||||
add(download_rate_speed);
|
||||
add(download_rate_string);
|
||||
add(upload_rate_double);
|
||||
add(upload_rate_speed);
|
||||
add(upload_rate_string);
|
||||
add(client);
|
||||
add(progress);
|
||||
|
@ -1155,9 +1162,9 @@ public:
|
|||
Gtk::TreeModelColumn<bool> was_updated;
|
||||
Gtk::TreeModelColumn<Glib::ustring> address;
|
||||
Gtk::TreeModelColumn<Glib::ustring> address_collated;
|
||||
Gtk::TreeModelColumn<double> download_rate_double;
|
||||
Gtk::TreeModelColumn<Speed> download_rate_speed;
|
||||
Gtk::TreeModelColumn<Glib::ustring> download_rate_string;
|
||||
Gtk::TreeModelColumn<double> upload_rate_double;
|
||||
Gtk::TreeModelColumn<Speed> upload_rate_speed;
|
||||
Gtk::TreeModelColumn<Glib::ustring> upload_rate_string;
|
||||
Gtk::TreeModelColumn<Glib::ustring> client;
|
||||
Gtk::TreeModelColumn<int> progress;
|
||||
|
@ -1217,25 +1224,28 @@ void initPeerRow(
|
|||
|
||||
void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const* peer)
|
||||
{
|
||||
std::string up_speed;
|
||||
std::string down_speed;
|
||||
std::string up_count;
|
||||
std::string down_count;
|
||||
std::string blocks_to_peer;
|
||||
std::string blocks_to_client;
|
||||
std::string cancelled_by_peer;
|
||||
std::string cancelled_by_client;
|
||||
|
||||
g_return_if_fail(peer != nullptr);
|
||||
|
||||
auto const down_speed = Speed{ peer->rateToClient_KBps, Speed::Units::KByps };
|
||||
auto const up_speed = Speed{ peer->rateToPeer_KBps, Speed::Units::KByps };
|
||||
|
||||
auto blocks_to_client = std::string{};
|
||||
auto blocks_to_peer = std::string{};
|
||||
auto cancelled_by_client = std::string{};
|
||||
auto cancelled_by_peer = std::string{};
|
||||
auto down_count = std::string{};
|
||||
auto down_speed_string = std::string{};
|
||||
auto up_count = std::string{};
|
||||
auto up_speed_string = std::string{};
|
||||
|
||||
if (peer->rateToPeer_KBps > 0.01)
|
||||
{
|
||||
up_speed = tr_formatter_speed_KBps(peer->rateToPeer_KBps);
|
||||
up_speed_string = up_speed.to_string();
|
||||
}
|
||||
|
||||
if (peer->rateToClient_KBps > 0)
|
||||
{
|
||||
down_speed = tr_formatter_speed_KBps(peer->rateToClient_KBps);
|
||||
down_speed_string = down_speed.to_string();
|
||||
}
|
||||
|
||||
if (peer->activeReqsToPeer > 0)
|
||||
|
@ -1273,10 +1283,10 @@ void refreshPeerRow(Gtk::TreeModel::iterator const& iter, tr_peer_stat const* pe
|
|||
(*iter)[peer_cols.upload_request_count_string] = up_count;
|
||||
(*iter)[peer_cols.download_request_count_number] = peer->activeReqsToPeer;
|
||||
(*iter)[peer_cols.download_request_count_string] = down_count;
|
||||
(*iter)[peer_cols.download_rate_double] = peer->rateToClient_KBps;
|
||||
(*iter)[peer_cols.download_rate_string] = down_speed;
|
||||
(*iter)[peer_cols.upload_rate_double] = peer->rateToPeer_KBps;
|
||||
(*iter)[peer_cols.upload_rate_string] = up_speed;
|
||||
(*iter)[peer_cols.download_rate_speed] = down_speed;
|
||||
(*iter)[peer_cols.download_rate_string] = down_speed_string;
|
||||
(*iter)[peer_cols.upload_rate_speed] = up_speed;
|
||||
(*iter)[peer_cols.upload_rate_string] = up_speed_string;
|
||||
(*iter)[peer_cols.flags] = std::data(peer->flagStr);
|
||||
(*iter)[peer_cols.was_updated] = true;
|
||||
(*iter)[peer_cols.blocks_downloaded_count_number] = peer->blocksToClient;
|
||||
|
@ -1317,7 +1327,7 @@ void DetailsDialog::Impl::refreshPeerList(std::vector<tr_torrent*> const& torren
|
|||
|
||||
auto make_key = [](tr_torrent const* tor, tr_peer_stat const* ps)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:d}.{:s}"), tr_torrentId(tor), ps->addr);
|
||||
return fmt::format("{:d}.{:s}", tr_torrentId(tor), ps->addr);
|
||||
};
|
||||
|
||||
/* step 3: add any new peers */
|
||||
|
@ -1385,7 +1395,7 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
|||
|
||||
auto make_key = [](tr_torrent const* tor, char const* url)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:d}.{:s}"), tr_torrentId(tor), url);
|
||||
return fmt::format("{:d}.{:s}", tr_torrentId(tor), url);
|
||||
};
|
||||
|
||||
/* step 1: mark all webseeds as not-updated */
|
||||
|
@ -1423,11 +1433,11 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
|||
auto const key = make_key(tor, webseed.url);
|
||||
auto const iter = store->get_iter(hash.at(key).get_path());
|
||||
|
||||
auto const KBps = double(webseed.download_bytes_per_second) / speed_K;
|
||||
auto const buf = webseed.is_downloading ? tr_formatter_speed_KBps(KBps) : std::string();
|
||||
auto const speed = Speed{ webseed.download_bytes_per_second, Speed::Units::Byps };
|
||||
auto const speed_string = webseed.is_downloading ? speed.to_string() : std::string{};
|
||||
|
||||
(*iter)[webseed_cols.download_rate_double] = KBps;
|
||||
(*iter)[webseed_cols.download_rate_string] = buf;
|
||||
(*iter)[webseed_cols.download_rate_speed] = speed;
|
||||
(*iter)[webseed_cols.download_rate_string] = speed_string;
|
||||
(*iter)[webseed_cols.was_updated] = true;
|
||||
}
|
||||
}
|
||||
|
@ -1575,25 +1585,9 @@ void setPeerViewColumns(Gtk::TreeView* peer_view)
|
|||
if (more)
|
||||
{
|
||||
view_columns.push_back(&peer_cols.download_request_count_string);
|
||||
}
|
||||
|
||||
if (more)
|
||||
{
|
||||
view_columns.push_back(&peer_cols.blocks_downloaded_count_string);
|
||||
}
|
||||
|
||||
if (more)
|
||||
{
|
||||
view_columns.push_back(&peer_cols.blocks_uploaded_count_string);
|
||||
}
|
||||
|
||||
if (more)
|
||||
{
|
||||
view_columns.push_back(&peer_cols.reqs_cancelled_by_client_count_string);
|
||||
}
|
||||
|
||||
if (more)
|
||||
{
|
||||
view_columns.push_back(&peer_cols.reqs_cancelled_by_peer_count_string);
|
||||
}
|
||||
|
||||
|
@ -1681,7 +1675,7 @@ void setPeerViewColumns(Gtk::TreeView* peer_view)
|
|||
r->property_xalign() = 1.0F;
|
||||
c = Gtk::make_managed<Gtk::TreeViewColumn>(_("Down"), *r);
|
||||
c->add_attribute(r->property_text(), *col);
|
||||
sort_col = &peer_cols.download_rate_double;
|
||||
sort_col = &peer_cols.download_rate_speed;
|
||||
}
|
||||
else if (*col == peer_cols.upload_rate_string)
|
||||
{
|
||||
|
@ -1689,7 +1683,7 @@ void setPeerViewColumns(Gtk::TreeView* peer_view)
|
|||
r->property_xalign() = 1.0F;
|
||||
c = Gtk::make_managed<Gtk::TreeViewColumn>(_("Up"), *r);
|
||||
c->add_attribute(r->property_text(), *col);
|
||||
sort_col = &peer_cols.upload_rate_double;
|
||||
sort_col = &peer_cols.upload_rate_speed;
|
||||
}
|
||||
else if (*col == peer_cols.client)
|
||||
{
|
||||
|
@ -1759,7 +1753,7 @@ void DetailsDialog::Impl::peer_page_init(Glib::RefPtr<Gtk::Builder> const& build
|
|||
auto* r = Gtk::make_managed<Gtk::CellRendererText>();
|
||||
auto* c = Gtk::make_managed<Gtk::TreeViewColumn>(_("Down"), *r);
|
||||
c->add_attribute(r->property_text(), webseed_cols.download_rate_string);
|
||||
c->set_sort_column(webseed_cols.download_rate_double);
|
||||
c->set_sort_column(webseed_cols.download_rate_speed);
|
||||
v->append_column(*c);
|
||||
}
|
||||
|
||||
|
@ -1963,7 +1957,7 @@ void buildTrackerSummary(
|
|||
gstr << text_dir_mark.at(static_cast<int>(direction));
|
||||
gstr << (tracker.isBackup ? "<i>" : "<b>");
|
||||
gstr << Glib::Markup::escape_text(
|
||||
!key.empty() ? fmt::format(FMT_STRING("{:s} - {:s}"), tracker.host_and_port, key) : tracker.host_and_port);
|
||||
!key.empty() ? fmt::format("{:s} - {:s}", tracker.host_and_port, key) : tracker.host_and_port);
|
||||
gstr << (tracker.isBackup ? "</i>" : "</b>");
|
||||
|
||||
if (!tracker.isBackup)
|
||||
|
@ -2380,7 +2374,7 @@ void AddTrackerDialog::on_response(int response)
|
|||
auto* const trackers = tr_variantDictAddList(args, TR_KEY_trackerAdd, 1);
|
||||
tr_variantListAddStr(trackers, url.raw());
|
||||
|
||||
core_->exec(&top);
|
||||
core_->exec(top);
|
||||
parent_.refresh();
|
||||
}
|
||||
else
|
||||
|
@ -2427,7 +2421,7 @@ void DetailsDialog::Impl::on_tracker_list_remove_button_clicked()
|
|||
auto* const trackers = tr_variantDictAddList(args, TR_KEY_trackerRemove, 1);
|
||||
tr_variantListAddInt(trackers, tracker_id);
|
||||
|
||||
core_->exec(&top);
|
||||
core_->exec(top);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2012-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2009-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -285,7 +285,7 @@ bool refreshFilesForeach(
|
|||
if (new_progress != old_progress)
|
||||
{
|
||||
(*iter)[file_cols.prog] = new_progress;
|
||||
(*iter)[file_cols.prog_str] = fmt::format(FMT_STRING("{:d}%"), new_progress);
|
||||
(*iter)[file_cols.prog_str] = fmt::format("{:d}%", new_progress);
|
||||
}
|
||||
|
||||
return false; /* keep walking */
|
||||
|
@ -725,24 +725,25 @@ bool FileList::Impl::onViewPathToggled(Gtk::TreeViewColumn* col, Gtk::TreeModel:
|
|||
|
||||
if (cid == file_cols.priority.index())
|
||||
{
|
||||
auto priority = iter->get_value(file_cols.priority);
|
||||
auto const old_priority = iter->get_value(file_cols.priority);
|
||||
auto new_priority = TR_PRI_NORMAL;
|
||||
|
||||
switch (priority)
|
||||
switch (old_priority)
|
||||
{
|
||||
case TR_PRI_NORMAL:
|
||||
priority = TR_PRI_HIGH;
|
||||
new_priority = TR_PRI_HIGH;
|
||||
break;
|
||||
|
||||
case TR_PRI_HIGH:
|
||||
priority = TR_PRI_LOW;
|
||||
new_priority = TR_PRI_LOW;
|
||||
break;
|
||||
|
||||
default:
|
||||
priority = TR_PRI_NORMAL;
|
||||
new_priority = TR_PRI_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
tr_torrentSetFilePriorities(tor, indexBuf.data(), indexBuf.size(), priority);
|
||||
tr_torrentSetFilePriorities(tor, indexBuf.data(), indexBuf.size(), new_priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2009-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2012-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2012-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2023-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2023-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -53,7 +53,7 @@ bool FreeSpaceLabel::Impl::on_freespace_timer()
|
|||
auto const capacity = tr_sys_path_get_capacity(dir_);
|
||||
auto const text = capacity ? fmt::format(_("{disk_space} free"), fmt::arg("disk_space", tr_strlsize(capacity->free))) :
|
||||
_("Error");
|
||||
label_.set_markup(fmt::format(FMT_STRING("<i>{:s}</i>"), text));
|
||||
label_.set_markup(fmt::format("<i>{:s}</i>", text));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
#include <giomm/contenttype.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional> // for std::less<>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <utility> // for std::move()
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
#endif
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/utils.h> // tr_formatter_speed_KBps()
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
#include <gdkmm/cursor.h>
|
||||
#include <gdkmm/rectangle.h>
|
||||
|
@ -61,6 +61,7 @@
|
|||
|
||||
using namespace std::string_literals;
|
||||
using namespace std::string_view_literals;
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
using VariantInt = Glib::Variant<int>;
|
||||
using VariantDouble = Glib::Variant<double>;
|
||||
|
@ -379,8 +380,8 @@ void MainWindow::Impl::syncAltSpeedButton()
|
|||
alt_speed_button_->set_tooltip_text(fmt::format(
|
||||
b ? _("Click to disable Alternative Speed Limits\n ({download_speed} down, {upload_speed} up)") :
|
||||
_("Click to enable Alternative Speed Limits\n ({download_speed} down, {upload_speed} up)"),
|
||||
fmt::arg("download_speed", tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_down))),
|
||||
fmt::arg("upload_speed", tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_alt_speed_up)))));
|
||||
fmt::arg("download_speed", Speed{ gtr_pref_int_get(TR_KEY_alt_speed_down), Speed::Units::KByps }.to_string()),
|
||||
fmt::arg("upload_speed", Speed{ gtr_pref_int_get(TR_KEY_alt_speed_up), Speed::Units::KByps }.to_string())));
|
||||
}
|
||||
|
||||
void MainWindow::Impl::alt_speed_toggled_cb()
|
||||
|
@ -451,7 +452,7 @@ Glib::RefPtr<Gio::MenuModel> MainWindow::Impl::createSpeedMenu(
|
|||
|
||||
for (auto const KBps : { 50, 100, 250, 500, 1000, 2500, 5000, 10000 })
|
||||
{
|
||||
auto item = Gio::MenuItem::create(tr_formatter_speed_KBps(KBps), full_stock_action_name);
|
||||
auto item = Gio::MenuItem::create(Speed{ KBps, Speed::Units::KByps }.to_string(), full_stock_action_name);
|
||||
item->set_action_and_target(full_stock_action_name, VariantInt::create(KBps));
|
||||
section->append_item(item);
|
||||
}
|
||||
|
@ -566,12 +567,12 @@ void MainWindow::Impl::onOptionsClicked()
|
|||
|
||||
update_menu(
|
||||
speed_menu_info_[TR_DOWN],
|
||||
tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_speed_limit_down)),
|
||||
Speed{ gtr_pref_int_get(TR_KEY_speed_limit_down), Speed::Units::KByps }.to_string(),
|
||||
TR_KEY_speed_limit_down_enabled);
|
||||
|
||||
update_menu(
|
||||
speed_menu_info_[TR_UP],
|
||||
tr_formatter_speed_KBps(gtr_pref_int_get(TR_KEY_speed_limit_up)),
|
||||
Speed{ gtr_pref_int_get(TR_KEY_speed_limit_up), Speed::Units::KByps }.to_string(),
|
||||
TR_KEY_speed_limit_up_enabled);
|
||||
|
||||
update_menu(
|
||||
|
@ -791,9 +792,9 @@ void MainWindow::Impl::updateSpeeds()
|
|||
if (session != nullptr)
|
||||
{
|
||||
auto dn_count = int{};
|
||||
auto dn_speed = double{};
|
||||
auto dn_speed = Speed{};
|
||||
auto up_count = int{};
|
||||
auto up_speed = double{};
|
||||
auto up_speed = Speed{};
|
||||
|
||||
auto const model = core_->get_model();
|
||||
for (auto i = 0U, count = model->get_n_items(); i < count; ++i)
|
||||
|
@ -805,10 +806,10 @@ void MainWindow::Impl::updateSpeeds()
|
|||
up_speed += torrent->get_speed_up();
|
||||
}
|
||||
|
||||
dl_lb_->set_text(fmt::format(_("{download_speed} ▼"), fmt::arg("download_speed", tr_formatter_speed_KBps(dn_speed))));
|
||||
dl_lb_->set_text(fmt::format(fmt::runtime(_("{download_speed} ▼")), fmt::arg("download_speed", dn_speed.to_string())));
|
||||
dl_lb_->set_visible(dn_count > 0);
|
||||
|
||||
ul_lb_->set_text(fmt::format(_("{upload_speed} ▲"), fmt::arg("upload_speed", tr_formatter_speed_KBps(up_speed))));
|
||||
ul_lb_->set_text(fmt::format(fmt::runtime(_("{upload_speed} ▲")), fmt::arg("upload_speed", up_speed.to_string())));
|
||||
ul_lb_->set_visible(dn_count > 0 || up_count > 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -14,7 +14,7 @@
|
|||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/error.h>
|
||||
#include <libtransmission/makemeta.h>
|
||||
#include <libtransmission/utils.h> /* tr_formatter_mem_B() */
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
#include <giomm/file.h>
|
||||
#include <glibmm/convert.h>
|
||||
|
@ -51,6 +51,7 @@
|
|||
#include <utility>
|
||||
|
||||
using namespace std::literals;
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
#if GTKMM_CHECK_VERSION(4, 0, 0)
|
||||
using FileListValue = Glib::Value<GSList*>;
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
BaseObjectType* cast_item,
|
||||
Glib::RefPtr<Gtk::Builder> const& builder,
|
||||
tr_metainfo_builder& metainfo_builder,
|
||||
std::future<tr_error*> future,
|
||||
std::future<tr_error> future,
|
||||
std::string_view target,
|
||||
Glib::RefPtr<Session> const& core);
|
||||
~MakeProgressDialog() override;
|
||||
|
@ -77,7 +78,7 @@ public:
|
|||
static std::unique_ptr<MakeProgressDialog> create(
|
||||
std::string_view target,
|
||||
tr_metainfo_builder& metainfo_builder,
|
||||
std::future<tr_error*> future,
|
||||
std::future<tr_error> future,
|
||||
Glib::RefPtr<Session> const& core);
|
||||
|
||||
[[nodiscard]] bool success() const
|
||||
|
@ -93,7 +94,7 @@ private:
|
|||
|
||||
private:
|
||||
tr_metainfo_builder& builder_;
|
||||
std::future<tr_error*> future_;
|
||||
std::future<tr_error> future_;
|
||||
std::string const target_;
|
||||
Glib::RefPtr<Session> const core_;
|
||||
bool success_ = false;
|
||||
|
@ -190,14 +191,14 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
|||
}
|
||||
else
|
||||
{
|
||||
tr_error* error = future_.get();
|
||||
auto error = future_.get();
|
||||
|
||||
if (error == nullptr)
|
||||
if (!error)
|
||||
{
|
||||
builder_.save(target_, &error);
|
||||
}
|
||||
|
||||
if (error == nullptr)
|
||||
if (!error)
|
||||
{
|
||||
str = fmt::format(_("Created '{path}'"), fmt::arg("path", base));
|
||||
success = true;
|
||||
|
@ -207,9 +208,8 @@ bool MakeProgressDialog::onProgressDialogRefresh()
|
|||
str = fmt::format(
|
||||
_("Couldn't create '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", base),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code));
|
||||
tr_error_free(error);
|
||||
fmt::arg("error", error.message()),
|
||||
fmt::arg("error_code", error.code()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ MakeProgressDialog::MakeProgressDialog(
|
|||
BaseObjectType* cast_item,
|
||||
Glib::RefPtr<Gtk::Builder> const& builder,
|
||||
tr_metainfo_builder& metainfo_builder,
|
||||
std::future<tr_error*> future,
|
||||
std::future<tr_error> future,
|
||||
std::string_view target,
|
||||
Glib::RefPtr<Session> const& core)
|
||||
: Gtk::Dialog(cast_item)
|
||||
|
@ -302,7 +302,7 @@ MakeProgressDialog::MakeProgressDialog(
|
|||
std::unique_ptr<MakeProgressDialog> MakeProgressDialog::create(
|
||||
std::string_view target,
|
||||
tr_metainfo_builder& metainfo_builder,
|
||||
std::future<tr_error*> future,
|
||||
std::future<tr_error> future,
|
||||
Glib::RefPtr<Session> const& core)
|
||||
{
|
||||
auto const builder = Gtk::Builder::create_from_resource(gtr_get_full_resource_path("MakeProgressDialog.ui"));
|
||||
|
@ -395,7 +395,7 @@ void MakeDialog::Impl::updatePiecesLabel()
|
|||
"({piece_count} BitTorrent pieces @ {piece_size})",
|
||||
builder_->piece_count()),
|
||||
fmt::arg("piece_count", builder_->piece_count()),
|
||||
fmt::arg("piece_size", tr_formatter_mem_B(builder_->piece_size())));
|
||||
fmt::arg("piece_size", Memory{ builder_->piece_size(), Memory::Units::Bytes }.to_string()));
|
||||
}
|
||||
|
||||
pieces_lb_->set_text(gstr);
|
||||
|
@ -542,7 +542,7 @@ MakeDialog::Impl::Impl(MakeDialog& dialog, Glib::RefPtr<Gtk::Builder> const& bui
|
|||
file_radio_->signal_toggled().connect([this]() { onSourceToggled(file_radio_, file_chooser_); });
|
||||
file_chooser_->signal_selection_changed().connect([this]() { onChooserChosen(file_chooser_); });
|
||||
|
||||
pieces_lb_->set_markup(fmt::format(FMT_STRING("<i>{:s}</i>"), _("No source selected")));
|
||||
pieces_lb_->set_markup(fmt::format("<i>{:s}</i>", _("No source selected")));
|
||||
|
||||
piece_size_scale_->set_visible(false);
|
||||
piece_size_scale_->signal_value_changed().connect([this]() { onPieceSizeUpdated(); });
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2010-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -118,7 +118,7 @@ void OptionsDialog::Impl::addResponseCB(int response)
|
|||
{
|
||||
if (response == TR_GTK_RESPONSE_TYPE(ACCEPT))
|
||||
{
|
||||
tr_torrentSetPriority(tor_, gtr_combo_box_get_active_enum(*priority_combo_));
|
||||
tr_torrentSetPriority(tor_, static_cast<tr_priority_t>(gtr_combo_box_get_active_enum(*priority_combo_)));
|
||||
|
||||
if (run_check_->get_active())
|
||||
{
|
||||
|
@ -334,23 +334,22 @@ void TorrentFileChooserDialog::onOpenDialogResponse(int response, Glib::RefPtr<S
|
|||
{
|
||||
if (response == TR_GTK_RESPONSE_TYPE(ACCEPT))
|
||||
{
|
||||
/* remember this folder the next time we use this dialog */
|
||||
gtr_pref_string_set(TR_KEY_open_dialog_dir, IF_GTKMM4(get_current_folder, get_current_folder_file)()->get_path());
|
||||
|
||||
bool const do_start = gtr_pref_flag_get(TR_KEY_start_added_torrents);
|
||||
bool const do_prompt = get_choice(std::string(ShowOptionsDialogChoice)) == "true";
|
||||
bool const do_notify = false;
|
||||
|
||||
#if GTKMM_CHECK_VERSION(4, 0, 0)
|
||||
auto files = std::vector<Glib::RefPtr<Gio::File>>();
|
||||
auto files_model = get_files();
|
||||
for (auto i = guint{ 0 }; i < files_model->get_n_items(); ++i)
|
||||
auto const files = IF_GTKMM4(get_files2, get_files)();
|
||||
g_assert(!files.empty());
|
||||
|
||||
/* remember this folder the next time we use this dialog */
|
||||
if (auto const folder = IF_GTKMM4(get_current_folder, get_current_folder_file)(); folder != nullptr)
|
||||
{
|
||||
files.push_back(gtr_ptr_dynamic_cast<Gio::File>(files_model->get_object(i)));
|
||||
gtr_pref_string_set(TR_KEY_open_dialog_dir, folder->get_path());
|
||||
}
|
||||
else if (auto const parent = files.front()->get_parent(); parent != nullptr)
|
||||
{
|
||||
gtr_pref_string_set(TR_KEY_open_dialog_dir, parent->get_path());
|
||||
}
|
||||
#else
|
||||
auto const files = get_files();
|
||||
#endif
|
||||
|
||||
core->add_files(files, do_start, do_prompt, do_notify);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2010-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
39
gtk/Prefs.cc
39
gtk/Prefs.cc
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2021-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
@ -25,13 +25,9 @@ void gtr_pref_init(std::string_view config_dir)
|
|||
gl_confdir = config_dir;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
**** Preferences
|
||||
****
|
||||
***/
|
||||
|
||||
[[nodiscard]] static std::string get_default_download_dir()
|
||||
namespace
|
||||
{
|
||||
[[nodiscard]] std::string get_default_download_dir()
|
||||
{
|
||||
if (auto dir = Glib::get_user_special_dir(TR_GLIB_USER_DIRECTORY(DOWNLOAD)); !std::empty(dir))
|
||||
{
|
||||
|
@ -50,7 +46,7 @@ void gtr_pref_init(std::string_view config_dir)
|
|||
* This is where we initialize the preferences file with the default values.
|
||||
* If you add a new preferences key, you /must/ add a default value here.
|
||||
*/
|
||||
[[nodiscard]] static tr_variant get_default_app_settings()
|
||||
[[nodiscard]] tr_variant get_default_app_settings()
|
||||
{
|
||||
auto const dir = get_default_download_dir();
|
||||
|
||||
|
@ -88,7 +84,7 @@ void gtr_pref_init(std::string_view config_dir)
|
|||
return tr_variant{ std::move(map) };
|
||||
}
|
||||
|
||||
static void ensure_sound_cmd_is_a_list(tr_variant* dict)
|
||||
void ensure_sound_cmd_is_a_list(tr_variant* dict)
|
||||
{
|
||||
tr_quark const key = TR_KEY_torrent_complete_sound_command;
|
||||
tr_variant* list = nullptr;
|
||||
|
@ -106,23 +102,20 @@ static void ensure_sound_cmd_is_a_list(tr_variant* dict)
|
|||
tr_variantListAddStr(list, "transmission torrent downloaded"sv);
|
||||
}
|
||||
|
||||
static tr_variant& getPrefs()
|
||||
tr_variant& getPrefs()
|
||||
{
|
||||
static auto settings = tr_variant{};
|
||||
|
||||
if (!settings.has_value())
|
||||
{
|
||||
settings = get_default_app_settings();
|
||||
settings.merge(tr_sessionLoadSettings(gl_confdir.c_str(), nullptr));
|
||||
auto const app_defaults = get_default_app_settings();
|
||||
settings.merge(tr_sessionLoadSettings(&app_defaults, gl_confdir.c_str(), nullptr));
|
||||
ensure_sound_cmd_is_a_list(&settings);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
} // namespace
|
||||
|
||||
tr_variant& gtr_pref_get_all()
|
||||
{
|
||||
|
@ -153,9 +146,7 @@ void gtr_pref_double_set(tr_quark const key, double value)
|
|||
tr_variantDictAddReal(&getPrefs(), key, value);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
// ---
|
||||
|
||||
bool gtr_pref_flag_get(tr_quark const key)
|
||||
{
|
||||
|
@ -169,9 +160,7 @@ void gtr_pref_flag_set(tr_quark const key, bool value)
|
|||
tr_variantDictAddBool(&getPrefs(), key, value);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
// ---
|
||||
|
||||
std::vector<std::string> gtr_pref_strv_get(tr_quark const key)
|
||||
{
|
||||
|
@ -207,9 +196,7 @@ void gtr_pref_string_set(tr_quark const key, std::string_view value)
|
|||
tr_variantDictAddStr(&getPrefs(), key, value);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
// ---
|
||||
|
||||
void gtr_pref_save(tr_session* session)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2005-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -49,6 +49,8 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
@ -840,20 +842,22 @@ public:
|
|||
SpeedPage::SpeedPage(BaseObjectType* cast_item, Glib::RefPtr<Gtk::Builder> const& builder, Glib::RefPtr<Session> const& core)
|
||||
: PageBase(cast_item, builder, core)
|
||||
{
|
||||
auto const speed_units_kbyps_str = Speed::units().display_name(Speed::Units::KByps);
|
||||
|
||||
localize_label(
|
||||
*init_check_button("upload_limit_check", TR_KEY_speed_limit_up_enabled),
|
||||
fmt::arg("speed_units", speed_K_str));
|
||||
fmt::arg("speed_units", speed_units_kbyps_str));
|
||||
init_spin_button("upload_limit_spin", TR_KEY_speed_limit_up, 0, std::numeric_limits<int>::max(), 5);
|
||||
|
||||
localize_label(
|
||||
*init_check_button("download_limit_check", TR_KEY_speed_limit_down_enabled),
|
||||
fmt::arg("speed_units", speed_K_str));
|
||||
fmt::arg("speed_units", speed_units_kbyps_str));
|
||||
init_spin_button("download_limit_spin", TR_KEY_speed_limit_down, 0, std::numeric_limits<int>::max(), 5);
|
||||
|
||||
localize_label(*get_widget<Gtk::Label>("alt_upload_limit_label"), fmt::arg("speed_units", speed_K_str));
|
||||
localize_label(*get_widget<Gtk::Label>("alt_upload_limit_label"), fmt::arg("speed_units", speed_units_kbyps_str));
|
||||
init_spin_button("alt_upload_limit_spin", TR_KEY_alt_speed_up, 0, std::numeric_limits<int>::max(), 5);
|
||||
|
||||
localize_label(*get_widget<Gtk::Label>("alt_download_limit_label"), fmt::arg("speed_units", speed_K_str));
|
||||
localize_label(*get_widget<Gtk::Label>("alt_download_limit_label"), fmt::arg("speed_units", speed_units_kbyps_str));
|
||||
init_spin_button("alt_download_limit_spin", TR_KEY_alt_speed_down, 0, std::numeric_limits<int>::max(), 5);
|
||||
|
||||
init_time_combo("alt_speed_start_time_combo", TR_KEY_alt_speed_time_begin);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2009-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -75,7 +75,7 @@ void RelocateDialog::Impl::startMovingNextTorrent()
|
|||
|
||||
if (tor != nullptr)
|
||||
{
|
||||
tr_torrentSetLocation(tor, targetLocation.c_str(), do_move_, nullptr, &done_);
|
||||
tr_torrentSetLocation(tor, targetLocation.c_str(), do_move_, &done_);
|
||||
}
|
||||
|
||||
torrent_ids_.pop_back();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2009-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2021-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// This file is licensed under the MIT (SPDX: MIT) license,
|
||||
// A copy of this license can be found in licenses/ .
|
||||
|
||||
|
@ -79,11 +79,11 @@ public:
|
|||
void torrents_added();
|
||||
|
||||
void add_files(std::vector<Glib::RefPtr<Gio::File>> const& files, bool do_start, bool do_prompt, bool do_notify);
|
||||
int add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify);
|
||||
void add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify);
|
||||
void add_torrent(Glib::RefPtr<Torrent> const& torrent, bool do_notify);
|
||||
bool add_from_url(Glib::ustring const& url);
|
||||
|
||||
void send_rpc_request(tr_variant const* request, int64_t tag, std::function<void(tr_variant&)> const& response_func);
|
||||
void send_rpc_request(tr_variant const& request, int64_t tag, std::function<void(tr_variant&)> const& response_func);
|
||||
|
||||
void commit_prefs_change(tr_quark key);
|
||||
|
||||
|
@ -690,12 +690,12 @@ Glib::RefPtr<Torrent> Session::Impl::create_new_torrent(tr_ctor* ctor)
|
|||
return Torrent::create(tor);
|
||||
}
|
||||
|
||||
int Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
|
||||
void Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
|
||||
{
|
||||
auto const* metainfo = tr_ctorGetMetainfo(ctor);
|
||||
if (metainfo == nullptr)
|
||||
{
|
||||
return TR_PARSE_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tr_torrentFindFromMetainfo(get_session(), metainfo) != nullptr)
|
||||
|
@ -709,18 +709,17 @@ int Session::Impl::add_ctor(tr_ctor* ctor, bool do_prompt, bool do_notify)
|
|||
}
|
||||
|
||||
tr_ctorFree(ctor);
|
||||
return TR_PARSE_DUPLICATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!do_prompt)
|
||||
{
|
||||
add_torrent(create_new_torrent(ctor), do_notify);
|
||||
tr_ctorFree(ctor);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
signal_add_prompt_.emit(ctor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -802,7 +801,7 @@ void Session::Impl::add_file_async_callback(
|
|||
|
||||
bool Session::Impl::add_file(Glib::RefPtr<Gio::File> const& file, bool do_start, bool do_prompt, bool do_notify)
|
||||
{
|
||||
auto const* const session = get_session();
|
||||
auto* const session = get_session();
|
||||
if (session == nullptr)
|
||||
{
|
||||
return false;
|
||||
|
@ -911,7 +910,7 @@ void Session::remove_torrent(tr_torrent_id_t id, bool delete_files)
|
|||
tr_torrentRemove(
|
||||
&torrent->get_underlying(),
|
||||
delete_files,
|
||||
[](char const* filename, void* /*user_data*/, tr_error** error)
|
||||
[](char const* filename, void* /*user_data*/, tr_error* error)
|
||||
{ return gtr_file_trash_or_remove(filename, error); },
|
||||
nullptr);
|
||||
}
|
||||
|
@ -968,7 +967,7 @@ void Session::start_now(tr_torrent_id_t id)
|
|||
auto* args = tr_variantDictAddDict(&top, TR_KEY_arguments, 1);
|
||||
auto* ids = tr_variantDictAddList(args, TR_KEY_ids, 1);
|
||||
tr_variantListAddInt(ids, id);
|
||||
exec(&top);
|
||||
exec(top);
|
||||
}
|
||||
|
||||
void Session::Impl::update()
|
||||
|
@ -1187,19 +1186,16 @@ bool core_read_rpc_response_idle(tr_variant& response)
|
|||
return false;
|
||||
}
|
||||
|
||||
void core_read_rpc_response(tr_session* /*session*/, tr_variant* response, gpointer /*user_data*/)
|
||||
void core_read_rpc_response(tr_session* /*session*/, tr_variant&& response)
|
||||
{
|
||||
auto owned_response = std::make_shared<tr_variant>();
|
||||
tr_variantInitBool(owned_response.get(), false);
|
||||
std::swap(*owned_response, *response);
|
||||
|
||||
auto owned_response = std::make_shared<tr_variant>(std::move(response));
|
||||
Glib::signal_idle().connect([owned_response]() mutable { return core_read_rpc_response_idle(*owned_response); });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Session::Impl::send_rpc_request(
|
||||
tr_variant const* request,
|
||||
tr_variant const& request,
|
||||
int64_t tag,
|
||||
std::function<void(tr_variant&)> const& response_func)
|
||||
{
|
||||
|
@ -1217,7 +1213,7 @@ void Session::Impl::send_rpc_request(
|
|||
gtr_message(fmt::format("request: [{}]", tr_variantToStr(request, TR_VARIANT_FMT_JSON_LEAN)));
|
||||
#endif
|
||||
|
||||
tr_rpc_request_exec_json(session_, request, core_read_rpc_response, nullptr);
|
||||
tr_rpc_request_exec(session_, request, core_read_rpc_response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1231,7 @@ void Session::port_test()
|
|||
tr_variantDictAddStrView(&request, TR_KEY_method, "port-test");
|
||||
tr_variantDictAddInt(&request, TR_KEY_tag, tag);
|
||||
impl_->send_rpc_request(
|
||||
&request,
|
||||
request,
|
||||
tag,
|
||||
[this](auto& response)
|
||||
{
|
||||
|
@ -1266,7 +1262,7 @@ void Session::blocklist_update()
|
|||
tr_variantDictAddStrView(&request, TR_KEY_method, "blocklist-update");
|
||||
tr_variantDictAddInt(&request, TR_KEY_tag, tag);
|
||||
impl_->send_rpc_request(
|
||||
&request,
|
||||
request,
|
||||
tag,
|
||||
[this](auto& response)
|
||||
{
|
||||
|
@ -1292,7 +1288,7 @@ void Session::blocklist_update()
|
|||
****
|
||||
***/
|
||||
|
||||
void Session::exec(tr_variant const* request)
|
||||
void Session::exec(tr_variant const& request)
|
||||
{
|
||||
auto const tag = nextTag;
|
||||
++nextTag;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2021-2023 Transmission authors and contributors.
|
||||
// This file Copyright © Transmission authors and contributors.
|
||||
// This file is licensed under the MIT (SPDX: MIT) license,
|
||||
// A copy of this license can be found in licenses/ .
|
||||
|
||||
|
@ -31,8 +31,8 @@ class Session : public Glib::Object
|
|||
public:
|
||||
enum ErrorCode
|
||||
{
|
||||
ERR_ADD_TORRENT_ERR = TR_PARSE_ERR,
|
||||
ERR_ADD_TORRENT_DUP = TR_PARSE_DUPLICATE,
|
||||
ERR_ADD_TORRENT_ERR = 1,
|
||||
ERR_ADD_TORRENT_DUP = 2,
|
||||
ERR_NO_MORE_TORRENTS = 1000 /* finished adding a batch */
|
||||
};
|
||||
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
|
||||
void blocklist_update();
|
||||
|
||||
void exec(tr_variant const* request);
|
||||
void exec(tr_variant const& request);
|
||||
|
||||
void open_folder(tr_torrent_id_t torrent_id) const;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2023-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2023-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -49,6 +49,7 @@
|
|||
#endif
|
||||
|
||||
using namespace std::literals;
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -214,6 +215,6 @@ std::string SystemTrayIcon::Impl::make_tooltip_text() const
|
|||
auto const* const session = core_->get_session();
|
||||
return fmt::format(
|
||||
_("{upload_speed} ▲ {download_speed} ▼"),
|
||||
fmt::arg("upload_speed", tr_formatter_speed_KBps(tr_sessionGetRawSpeed_KBps(session, TR_UP))),
|
||||
fmt::arg("download_speed", tr_formatter_speed_KBps(tr_sessionGetRawSpeed_KBps(session, TR_DOWN))));
|
||||
fmt::arg("upload_speed", Speed{ tr_sessionGetRawSpeed_KBps(session, TR_UP), Speed::Units::KByps }.to_string()),
|
||||
fmt::arg("download_speed", Speed{ tr_sessionGetRawSpeed_KBps(session, TR_DOWN), Speed::Units::KByps }.to_string()));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/utils.h>
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
#include <glibmm/i18n.h>
|
||||
#include <glibmm/value.h>
|
||||
|
@ -24,6 +25,8 @@
|
|||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -137,12 +140,15 @@ public:
|
|||
|
||||
std::string_view mime_type;
|
||||
|
||||
uint64_t have_unchecked = {};
|
||||
uint64_t have_valid = {};
|
||||
uint64_t left_until_done = {};
|
||||
uint64_t size_when_done = {};
|
||||
uint64_t total_size = {};
|
||||
uint64_t uploaded_ever = {};
|
||||
Storage have_unchecked = {};
|
||||
Storage have_valid = {};
|
||||
Storage left_until_done = {};
|
||||
Storage size_when_done = {};
|
||||
Storage total_size = {};
|
||||
Storage uploaded_ever = {};
|
||||
|
||||
Speed speed_down = {};
|
||||
Speed speed_up = {};
|
||||
|
||||
size_t queue_position = {};
|
||||
|
||||
|
@ -171,8 +177,6 @@ public:
|
|||
|
||||
float ratio = {};
|
||||
float seed_ratio = {};
|
||||
float speed_down = {};
|
||||
float speed_up = {};
|
||||
|
||||
tr_priority_t priority = {};
|
||||
|
||||
|
@ -241,10 +245,19 @@ Torrent::ChangeFlags Torrent::Impl::update_cache()
|
|||
|
||||
auto seed_ratio = 0.0;
|
||||
auto const has_seed_ratio = tr_torrentGetSeedRatio(raw_torrent_, &seed_ratio);
|
||||
auto const view = tr_torrentView(raw_torrent_);
|
||||
|
||||
update_cache_value(cache_.name, tr_torrentName(raw_torrent_), result, ChangeFlag::NAME);
|
||||
update_cache_value(cache_.speed_up, stats->pieceUploadSpeed_KBps, 0.01F, result, ChangeFlag::SPEED_UP);
|
||||
update_cache_value(cache_.speed_down, stats->pieceDownloadSpeed_KBps, 0.01F, result, ChangeFlag::SPEED_DOWN);
|
||||
update_cache_value(cache_.name, view.name, result, ChangeFlag::NAME);
|
||||
update_cache_value(
|
||||
cache_.speed_up,
|
||||
Speed{ stats->pieceUploadSpeed_KBps, Speed::Units::KByps },
|
||||
result,
|
||||
ChangeFlag::SPEED_UP);
|
||||
update_cache_value(
|
||||
cache_.speed_down,
|
||||
Speed{ stats->pieceDownloadSpeed_KBps, Speed::Units::KByps },
|
||||
result,
|
||||
ChangeFlag::SPEED_DOWN);
|
||||
update_cache_value(cache_.active_peers_up, stats->peersGettingFromUs, result, ChangeFlag::ACTIVE_PEERS_UP);
|
||||
update_cache_value(
|
||||
cache_.active_peers_down,
|
||||
|
@ -290,16 +303,36 @@ Torrent::ChangeFlags Torrent::Impl::update_cache()
|
|||
Percents(stats->seedRatioPercentDone),
|
||||
result,
|
||||
ChangeFlag::SEED_RATIO_PERCENT_DONE);
|
||||
update_cache_value(cache_.total_size, tr_torrentTotalSize(raw_torrent_), result, ChangeFlag::TOTAL_SIZE);
|
||||
update_cache_value(cache_.total_size, Storage{ view.total_size, Storage::Units::Bytes }, result, ChangeFlag::TOTAL_SIZE);
|
||||
|
||||
update_cache_value(cache_.has_seed_ratio, has_seed_ratio, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.have_unchecked, stats->haveUnchecked, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.have_valid, stats->haveValid, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.left_until_done, stats->leftUntilDone, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(
|
||||
cache_.have_unchecked,
|
||||
Storage{ stats->haveUnchecked, Storage::Units::Bytes },
|
||||
result,
|
||||
ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(
|
||||
cache_.have_valid,
|
||||
Storage{ stats->haveValid, Storage::Units::Bytes },
|
||||
result,
|
||||
ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(
|
||||
cache_.left_until_done,
|
||||
Storage{ stats->leftUntilDone, Storage::Units::Bytes },
|
||||
result,
|
||||
ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.percent_done, Percents(stats->percentDone), result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.seed_ratio, static_cast<float>(seed_ratio), 0.01F, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.size_when_done, stats->sizeWhenDone, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(cache_.uploaded_ever, stats->uploadedEver, result, ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(
|
||||
cache_.size_when_done,
|
||||
Storage{ stats->sizeWhenDone, Storage::Units::Bytes },
|
||||
result,
|
||||
ChangeFlag::LONG_PROGRESS);
|
||||
update_cache_value(
|
||||
cache_.uploaded_ever,
|
||||
Storage{ stats->uploadedEver, Storage::Units::Bytes },
|
||||
result,
|
||||
ChangeFlag::LONG_PROGRESS);
|
||||
|
||||
update_cache_value(
|
||||
cache_.metadata_percent_complete,
|
||||
|
@ -313,7 +346,7 @@ Torrent::ChangeFlags Torrent::Impl::update_cache()
|
|||
|
||||
if (result.test(ChangeFlag::NAME))
|
||||
{
|
||||
cache_.name_collated = fmt::format("{}\t{}", cache_.name.lowercase(), tr_torrentView(raw_torrent_).hash_string);
|
||||
cache_.name_collated = fmt::format("{}\t{}", cache_.name.lowercase(), view.hash_string);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -409,7 +442,7 @@ Glib::ustring Torrent::Impl::get_short_status_text() const
|
|||
case TR_STATUS_DOWNLOAD:
|
||||
case TR_STATUS_SEED:
|
||||
return fmt::format(
|
||||
FMT_STRING("{:s} {:s}"),
|
||||
"{:s} {:s}",
|
||||
get_short_transfer_text(),
|
||||
fmt::format(_("Ratio: {ratio}"), fmt::arg("ratio", tr_strlratio(cache_.ratio))));
|
||||
|
||||
|
@ -422,7 +455,7 @@ Glib::ustring Torrent::Impl::get_long_progress_text() const
|
|||
{
|
||||
Glib::ustring gstr;
|
||||
|
||||
bool const isDone = cache_.left_until_done == 0;
|
||||
bool const isDone = cache_.left_until_done.is_zero();
|
||||
auto const haveTotal = cache_.have_unchecked + cache_.have_valid;
|
||||
bool const isSeed = cache_.have_valid >= cache_.total_size;
|
||||
|
||||
|
@ -515,7 +548,7 @@ Glib::ustring Torrent::Impl::get_long_status_text() const
|
|||
default:
|
||||
if (auto const buf = get_short_transfer_text(); !std::empty(buf))
|
||||
{
|
||||
status_str += fmt::format(FMT_STRING(" - {:s}"), buf);
|
||||
status_str += fmt::format(" - {:s}", buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -581,14 +614,14 @@ Glib::ustring Torrent::Impl::get_short_transfer_text() const
|
|||
if (cache_.has_metadata && cache_.active_peers_down > 0)
|
||||
{
|
||||
return fmt::format(
|
||||
_("{download_speed} ▼ {upload_speed} ▲"),
|
||||
fmt::arg("upload_speed", tr_formatter_speed_KBps(cache_.speed_up)),
|
||||
fmt::arg("download_speed", tr_formatter_speed_KBps(cache_.speed_down)));
|
||||
fmt::runtime(_("{download_speed} ▼ {upload_speed} ▲")),
|
||||
fmt::arg("upload_speed", cache_.speed_up.to_string()),
|
||||
fmt::arg("download_speed", cache_.speed_down.to_string()));
|
||||
}
|
||||
|
||||
if (cache_.has_metadata && cache_.active_peers_up > 0)
|
||||
{
|
||||
return fmt::format(_("{upload_speed} ▲"), fmt::arg("upload_speed", tr_formatter_speed_KBps(cache_.speed_up)));
|
||||
return fmt::format(fmt::runtime(_("{upload_speed} ▲")), fmt::arg("upload_speed", cache_.speed_up.to_string()));
|
||||
}
|
||||
|
||||
if (cache_.stalled)
|
||||
|
@ -714,12 +747,12 @@ tr_torrent& Torrent::get_underlying() const
|
|||
return *impl_->get_raw_torrent();
|
||||
}
|
||||
|
||||
float Torrent::get_speed_up() const
|
||||
Speed Torrent::get_speed_up() const
|
||||
{
|
||||
return impl_->get_cache().speed_up;
|
||||
}
|
||||
|
||||
float Torrent::get_speed_down() const
|
||||
Speed Torrent::get_speed_down() const
|
||||
{
|
||||
return impl_->get_cache().speed_down;
|
||||
}
|
||||
|
@ -784,7 +817,7 @@ int Torrent::get_active_peer_count() const
|
|||
return impl_->get_cache().active_peer_count;
|
||||
}
|
||||
|
||||
uint64_t Torrent::get_total_size() const
|
||||
Storage Torrent::get_total_size() const
|
||||
{
|
||||
return impl_->get_cache().total_size;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include "Flags.h"
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
#include <giomm/icon.h>
|
||||
#include <glibmm/extraclassinit.h>
|
||||
|
@ -71,6 +72,9 @@ public:
|
|||
using ChangeFlags = Flags<ChangeFlag>;
|
||||
|
||||
public:
|
||||
using Speed = libtransmission::Values::Speed;
|
||||
using Storage = libtransmission::Values::Storage;
|
||||
|
||||
int get_active_peer_count() const;
|
||||
int get_active_peers_down() const;
|
||||
int get_active_peers_up() const;
|
||||
|
@ -92,10 +96,10 @@ public:
|
|||
float get_ratio() const;
|
||||
Percents get_recheck_progress() const;
|
||||
Percents get_seed_ratio_percent_done() const;
|
||||
float get_speed_down() const;
|
||||
float get_speed_up() const;
|
||||
Speed get_speed_down() const;
|
||||
Speed get_speed_up() const;
|
||||
tr_torrent& get_underlying() const;
|
||||
uint64_t get_total_size() const;
|
||||
Storage get_total_size() const;
|
||||
unsigned int get_trackers() const;
|
||||
|
||||
Glib::RefPtr<Gio::Icon> get_icon() const;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -420,7 +420,7 @@ void TorrentCellRenderer::Impl::render_compact(
|
|||
icon_renderer_->render(context, widget, icon_area, icon_area, flags);
|
||||
|
||||
progress_renderer_->property_value() = percent_done;
|
||||
progress_renderer_->property_text() = fmt::format(FMT_STRING("{:d}%"), percent_done);
|
||||
progress_renderer_->property_text() = fmt::format("{:d}%", percent_done);
|
||||
progress_renderer_->property_sensitive() = sensitive;
|
||||
render_progress_bar(context, widget, prog_area, flags, progress_color);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2007-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2022-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
|
60
gtk/Utils.cc
60
gtk/Utils.cc
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -13,6 +13,7 @@
|
|||
#include <libtransmission/error.h>
|
||||
#include <libtransmission/torrent-metainfo.h>
|
||||
#include <libtransmission/utils.h> /* tr_strratio() */
|
||||
#include <libtransmission/values.h>
|
||||
#include <libtransmission/version.h> /* SHORT_VERSION_STRING */
|
||||
#include <libtransmission/web-utils.h>
|
||||
|
||||
|
@ -58,27 +59,7 @@
|
|||
|
||||
using namespace std::literals;
|
||||
|
||||
/***
|
||||
**** UNITS
|
||||
***/
|
||||
|
||||
int const mem_K = 1024;
|
||||
char const* const mem_K_str = N_("KiB");
|
||||
char const* const mem_M_str = N_("MiB");
|
||||
char const* const mem_G_str = N_("GiB");
|
||||
char const* const mem_T_str = N_("TiB");
|
||||
|
||||
int const disk_K = 1000;
|
||||
char const* const disk_K_str = N_("kB");
|
||||
char const* const disk_M_str = N_("MB");
|
||||
char const* const disk_G_str = N_("GB");
|
||||
char const* const disk_T_str = N_("TB");
|
||||
|
||||
int const speed_K = 1000;
|
||||
char const* const speed_K_str = N_("kB/s");
|
||||
char const* const speed_M_str = N_("MB/s");
|
||||
char const* const speed_G_str = N_("GB/s");
|
||||
char const* const speed_T_str = N_("TB/s");
|
||||
using namespace libtransmission::Values;
|
||||
|
||||
/***
|
||||
****
|
||||
|
@ -132,9 +113,14 @@ Glib::ustring tr_strlratio(double ratio)
|
|||
return tr_strratio(ratio, gtr_get_unicode_string(GtrUnicode::Inf).c_str());
|
||||
}
|
||||
|
||||
Glib::ustring tr_strlsize(guint64 size_in_bytes)
|
||||
Glib::ustring tr_strlsize(libtransmission::Values::Storage const& storage)
|
||||
{
|
||||
return size_in_bytes == 0 ? Q_("None") : tr_formatter_size_B(size_in_bytes);
|
||||
return storage.is_zero() ? Q_("None") : storage.to_string();
|
||||
}
|
||||
|
||||
Glib::ustring tr_strlsize(guint64 n_bytes)
|
||||
{
|
||||
return tr_strlsize(Storage{ n_bytes, Storage::Units::Bytes });
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -524,14 +510,18 @@ void setup_item_view_button_event_handling(
|
|||
|
||||
#endif
|
||||
|
||||
bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error)
|
||||
bool gtr_file_trash_or_remove(std::string const& filename, tr_error* error)
|
||||
{
|
||||
bool trashed = false;
|
||||
bool result = true;
|
||||
|
||||
g_return_val_if_fail(!filename.empty(), false);
|
||||
|
||||
auto local_error = tr_error{};
|
||||
if (error == nullptr)
|
||||
{
|
||||
error = &local_error;
|
||||
}
|
||||
|
||||
auto const file = Gio::File::create_for_path(filename);
|
||||
bool trashed = false;
|
||||
|
||||
if (gtr_pref_flag_get(TR_KEY_trash_can_enabled))
|
||||
{
|
||||
|
@ -541,15 +531,16 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error)
|
|||
}
|
||||
catch (Glib::Error const& e)
|
||||
{
|
||||
error->set(e.code(), TR_GLIB_EXCEPTION_WHAT(e));
|
||||
gtr_message(fmt::format(
|
||||
_("Couldn't move '{path}' to trash: {error} ({error_code})"),
|
||||
fmt::arg("path", filename),
|
||||
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
|
||||
fmt::arg("error_code", e.code())));
|
||||
tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e));
|
||||
fmt::arg("error", error->message()),
|
||||
fmt::arg("error_code", error->code())));
|
||||
}
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
if (!trashed)
|
||||
{
|
||||
try
|
||||
|
@ -558,13 +549,12 @@ bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error)
|
|||
}
|
||||
catch (Glib::Error const& e)
|
||||
{
|
||||
error->set(e.code(), TR_GLIB_EXCEPTION_WHAT(e));
|
||||
gtr_message(fmt::format(
|
||||
_("Couldn't remove '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", filename),
|
||||
fmt::arg("error", TR_GLIB_EXCEPTION_WHAT(e)),
|
||||
fmt::arg("error_code", e.code())));
|
||||
tr_error_clear(error);
|
||||
tr_error_set(error, e.code(), TR_GLIB_EXCEPTION_WHAT(e));
|
||||
fmt::arg("error", error->message()),
|
||||
fmt::arg("error_code", error->code())));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
|
28
gtk/Utils.h
28
gtk/Utils.h
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2008-2023 Mnemosyne LLC.
|
||||
// This file Copyright © Mnemosyne LLC.
|
||||
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
||||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <libtransmission/transmission.h>
|
||||
#include <libtransmission/tr-macros.h>
|
||||
#include <libtransmission/values.h>
|
||||
|
||||
#include <glibmm/objectbase.h>
|
||||
#include <glibmm/refptr.h>
|
||||
|
@ -43,28 +44,6 @@
|
|||
****
|
||||
***/
|
||||
|
||||
extern int const mem_K;
|
||||
extern char const* const mem_K_str;
|
||||
extern char const* const mem_M_str;
|
||||
extern char const* const mem_G_str;
|
||||
extern char const* const mem_T_str;
|
||||
|
||||
extern int const disk_K;
|
||||
extern char const* const disk_K_str;
|
||||
extern char const* const disk_M_str;
|
||||
extern char const* const disk_G_str;
|
||||
extern char const* const disk_T_str;
|
||||
|
||||
extern int const speed_K;
|
||||
extern char const* const speed_K_str;
|
||||
extern char const* const speed_M_str;
|
||||
extern char const* const speed_G_str;
|
||||
extern char const* const speed_T_str;
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
void gtr_message(std::string const& message);
|
||||
void gtr_warning(std::string const& message);
|
||||
void gtr_error(std::string const& message);
|
||||
|
@ -85,6 +64,7 @@ Glib::ustring gtr_get_unicode_string(GtrUnicode uni);
|
|||
|
||||
/* return a human-readable string for the size given in bytes. */
|
||||
Glib::ustring tr_strlsize(guint64 size_in_bytes);
|
||||
Glib::ustring tr_strlsize(libtransmission::Values::Storage const& storage);
|
||||
|
||||
/* return a human-readable string for the given ratio. */
|
||||
Glib::ustring tr_strlratio(double ratio);
|
||||
|
@ -185,7 +165,7 @@ void setup_item_view_button_event_handling(
|
|||
#endif
|
||||
|
||||
/* move a file to the trashcan if GIO is available; otherwise, delete it */
|
||||
bool gtr_file_trash_or_remove(std::string const& filename, tr_error** error);
|
||||
bool gtr_file_trash_or_remove(std::string const& filename, tr_error* error = nullptr);
|
||||
|
||||
void gtr_paste_clipboard_url_into_entry(Gtk::Entry& entry);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue