Skip to content

Commit

Permalink
Merge pull request #5 from clajiness/v0.5
Browse files Browse the repository at this point in the history
V0.5
  • Loading branch information
clajiness authored Dec 2, 2024
2 parents 5043de6 + e540a75 commit 2d3e018
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 49 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ A tool for keeping ProtonVPN, OPNsense, and qBittorrent ports in sync.
## Purpose
This tool helps automate port forwarding from ProtonVPN to qBittorrent via OPNsense. The tool polls ProtonVPN for the given forwarded port, checks the port set in OPNsense and qBittorrent, and updates it if necessary.

Version v0.5 and later allows you to skip qBittorrent and just sync Proton's forwarded port to OPNsense.

## Docker Install
I recommend using the provided Docker container to simplify the set up of qbop. An example Docker Compose file is provided.

Expand All @@ -28,9 +30,10 @@ I'd recommend using Docker Compose to configure and run your instance of qbop. T
4. `OPN_API_KEY:` Your OPNsense API key - https://docs.opnsense.org/development/how-tos/api.html
5. `OPN_API_SECRET:` Your OPNsense API secret
6. `OPN_PROTON_ALIAS_NAME:` The firewall alias that you use for ProtonVPN's forwarded port. For example, `proton_vpn_forwarded_port`.
7. `QBIT_ADDR:` The IP address of your qBittorrent app. For example, `http://10.1.1.100:8080`.
8. `QBIT_USER:` Your qBittorrent username
9. `QBIT_PASS:` Your qBittorrent password
7. `QBIT_SKIP:` [true/false] Skip qBittorrent. If true, subsequent qBit environment variables are not necessary.
8. `QBIT_ADDR:` The IP address of your qBittorrent app. For example, `http://10.1.1.100:8080`.
9. `QBIT_USER:` Your qBittorrent username
10. `QBIT_PASS:` Your qBittorrent password

## Native Install

Expand All @@ -51,8 +54,9 @@ Clone the qbop repo to your machine. Remove the existing file `config.yml`. Copy
4. `opnsense_api_key:` Your OPNsense API key - https://docs.opnsense.org/development/how-tos/api.html
5. `opnsense_api_secret:` Your OPNsense API secret
6. `opnsense_alias_name:` The firewall alias that you use for ProtonVPN's forwarded port. For example, `proton_vpn_forwarded_port`.
7. `qbit_addr:` The IP address of your qBittorrent app. For example, `http://10.1.1.100:8080`.
8. `qbit_user:` Your qBittorrent username
9. `qbit_pass:` Your qBittorrent password
7. `qbit_skip:` [true/false] Skip qBittorrent. If true, subsequent qBit environment variables are not necessary.
8. `qbit_addr:` The IP address of your qBittorrent app. For example, `http://10.1.1.100:8080`.
9. `qbit_user:` Your qBittorrent username
10. `qbit_pass:` Your qBittorrent password

Next, you must start the script. You can manually start it, if you wish, with `ruby qbop.rb`. I'd recommend setting it up to start on boot, though. I've included an example systemd service file for those on Linux.
1 change: 1 addition & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ opnsense_api_secret: <%= ENV["OPN_API_SECRET"] %>
opnsense_alias_name: <%= ENV["OPN_PROTON_ALIAS_NAME"] %>

# qBit
qbit_skip: <%= ENV["QBIT_SKIP"] %>
qbit_addr: <%= ENV["QBIT_ADDR"] %>
qbit_user: <%= ENV["QBIT_USER"] %>
qbit_pass: <%= ENV["QBIT_PASS"] %>
1 change: 1 addition & 0 deletions config.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ opnsense_api_secret:
opnsense_alias_name: proton_vpn_forwarded_port

# qBit
qbit_skip: [true/false]
qbit_addr: http://
qbit_user:
qbit_pass:
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ services:
- PROTON_GATEWAY=
- OPN_INTERFACE_ADDR=
- OPN_API_KEY=
- OPN_API_SECRET=
- OPN_API_SECRET=
- OPN_PROTON_ALIAS_NAME=
- QBIT_ADDR=
- QBIT_SKIP=
- QBIT_ADDR=
- QBIT_USER=
- QBIT_PASS=

Expand Down
84 changes: 44 additions & 40 deletions qbop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,57 +147,61 @@ def parse_config
end

# qBit section
begin
# create qBit object
qbit ||= Service::Qbit.new
unless config["qbit_skip"].nil? || config["qbit_skip"].to_s.downcase == "true"
begin
# create qBit object
qbit ||= Service::Qbit.new

# get sid from qBit
sid = qbit.qbt_auth_login(config)
# get sid from qBit
sid = qbit.qbt_auth_login(config)

# get port from qBit
qbt_port = qbit.qbt_app_preferences(config, sid)
# get port from qBit
qbt_port = qbit.qbt_app_preferences(config, sid)

if qbt_port != forwarded_port
@logger.info("qBit port #{qbt_port} does not match Proton forwarded port #{forwarded_port}. Attempt #{counter[:qbit_attempt]} of 3.")
if qbt_port != forwarded_port
@logger.info("qBit port #{qbt_port} does not match Proton forwarded port #{forwarded_port}. Attempt #{counter[:qbit_attempt]} of 3.")

# after 3 attempts, if the ports still don't match, set the qBit port to be updated
if counter[:port] == forwarded_port && counter[:qbit_attempt] > 2
counter[:qbit_change] = true
# after 3 attempts, if the ports still don't match, set the qBit port to be updated
if counter[:port] == forwarded_port && counter[:qbit_attempt] > 2
counter[:qbit_change] = true
end
else
# reset counter if ports match
counter[:qbit_attempt] = 1 if counter[:qbit_attempt] != 1
@logger.info("qBit port #{qbt_port} matches Proton forwarded port #{forwarded_port}")
end
else
# reset counter if ports match
counter[:qbit_attempt] = 1 if counter[:qbit_attempt] != 1
@logger.info("qBit port #{qbt_port} matches Proton forwarded port #{forwarded_port}")
end

# keep track of how many times the qBit and Proton ports don't match
if qbt_port != forwarded_port
counter[:port] = forwarded_port
counter[:qbit_attempt] += 1
end
# keep track of how many times the qBit and Proton ports don't match
if qbt_port != forwarded_port
counter[:port] = forwarded_port
counter[:qbit_attempt] += 1
end

# set qBit port if counter is set to true
if counter[:qbit_change] == true
# set qBit port
response = qbit.qbt_app_set_preferences(config, forwarded_port, sid)
# set qBit port if counter is set to true
if counter[:qbit_change] == true
# set qBit port
response = qbit.qbt_app_set_preferences(config, forwarded_port, sid)

if response.code == "200"
@logger.info("qBit's port has been updated to #{forwarded_port}")
if response.code == "200"
@logger.info("qBit's port has been updated to #{forwarded_port}")

# reset counter
counter[:qbit_change] = false
counter[:qbit_attempt] = 1
else
@logger.error("qBit's port was not updated")
# reset counter
counter[:qbit_change] = false
counter[:qbit_attempt] = 1
else
@logger.error("qBit's port was not updated")
end
end
end
rescue Exception => e
@logger.error("qBit has returned an error:")
@logger.error(e)
rescue Exception => e
@logger.error("qBit has returned an error:")
@logger.error(e)

@logger.info("sleeping for #{config['loop_freq'].to_i} seconds and trying again")
sleep config["loop_freq"].to_i
next
@logger.info("sleeping for #{config['loop_freq'].to_i} seconds and trying again")
sleep config["loop_freq"].to_i
next
end
else
@logger.info("qBit check skipped")
end

# sleep before looping again
Expand Down
2 changes: 1 addition & 1 deletion version.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
version: 0.4.1
version: 0.5.1

0 comments on commit 2d3e018

Please sign in to comment.