qbittorrent / qBittorrent

qBittorrent BitTorrent client
https://www.qbittorrent.org
Other
28.62k stars 4.01k forks source link

WebUI: Add way to mass update announce url #11868

Open lordvalium opened 4 years ago

lordvalium commented 4 years ago

Has been implemented in Application but not WebUi. Can that please be updated?

https://github.com/qbittorrent/qBittorrent/blob/master/Changelog

Tue Dec 03 2019 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v4.2.0
      - FEATURE: Add "Tracker entries" dialog (Chocobo1)

Commit : 9e7f505

Screenshot

https://github.com/qbittorrent/qBittorrent/issues/2428#issuecomment-573396594

Efreak commented 4 years ago

I believe this is available in the web API. I was able to do this via a python script when I had to change my token on a tracker.

magneticflux- commented 4 years ago

As a workaround, I re-wrote this Fish shell snippet to update all torrents with a bulk tracker list:

set username "my_username"
set password "my_password"
set url "my_url"
set trackers (curl --silent --stderr -- "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt")
qbt torrent list --url "$url" --username "$username" --password "$password" -F json | jq ".[].hash" -r | parallel --eta --bar -N1 echo $trackers '|' xargs qbt torrent tracker add --url "$url" --username "$username" --password "$password" {}

It requires qbittorrent-cli, jq, GNU Parallel, and xargs.

Now updated to support many trackers and many torrents! Previously, too many trackers would reach the shell's argument limit. Now, they get split by xargs if they're too long. Also, each torrent is now updated in parallel, with a progress bar. Increase the job limit with -j100 if your server can handle it!

For a bash or probably any other shell version, replace set x y with x=y and set x (y) with x=$(y).

The same script also works for removing trackers! Replace xargs qbt torrent tracker add with xargs -n1 qbt torrent tracker delete and specify which trackers to delete using $trackers!

BonzTM commented 3 years ago

As a workaround, I wrote this Fish shell snippet to update all torrents with an up-to-date tracker list:

set trackers (curl --silent --stderr -- "https://newtrackon.com/api/stable")
for hash in (qbt torrent list --url "$url" --username "$username" --password "$password" -F json | jq ".[].hash" -r)
    echo "Processing $hash"
    qbt torrent tracker add --url "$url" --username "$username"--password "$password" "$hash" "$trackers"
end

It requires qbittorrent-cli and jq.

I also basically did the same thing on 1000 mixed torrents to update just some trackers from http to https.

  1. Got a list of the hashes with qbt torrent list -F json | jq ".[].hash" -r >> hash_list
  2. Iterated through all the hashes with a shell script
    #! /bin/bash
    for x in $(cat hash_list); do
    trackerurl=$(qbt torrent tracker list $x -F json | jq '.[]."Url"')
    if [[ $trackerurl == *http://oldtracker.com* ]]; then
    echo "Updating $x for https"
    qbt torrent tracker add $x "https://newtracker.com/announce"
    qbt torrent tracker delete $x "http://oldtracker.com/announce"
    else
    echo "$x has tracker $trackerurl"
    fi;
    done;

Would still love to see this functionality in the WebUI. Although the time it took to loop through and change all of these via API might not work well in the WebUI.

ghost commented 2 years ago

As a workaround, I wrote this Fish shell snippet to update all torrents with an up-to-date tracker list:

set trackers (curl --silent --stderr -- "https://newtrackon.com/api/stable")
for hash in (qbt torrent list --url "$url" --username "$username" --password "$password" -F json | jq ".[].hash" -r)
    echo "Processing $hash"
    qbt torrent tracker add --url "$url" --username "$username"--password "$password" "$hash" "$trackers"
end

It requires qbittorrent-cli and jq.

I also basically did the same thing on 1000 mixed torrents to update just some trackers from http to https.

  1. Got a list of the hashes with qbt torrent list -F json | jq ".[].hash" -r >> hash_list
  2. Iterated through all the hashes with a shell script
#! /bin/bash
for x in $(cat hash_list); do
 trackerurl=$(qbt torrent tracker list $x -F json | jq '.[]."Url"')
 if [[ $trackerurl == *http://oldtracker.com* ]]; then
  echo "Updating $x for https"
  qbt torrent tracker add $x "https://newtracker.com/announce"
  qbt torrent tracker delete $x "http://oldtracker.com/announce"
 else
  echo "$x has tracker $trackerurl"
 fi;
done;

Would still love to see this functionality in the WebUI. Although the time it took to loop through and change all of these via API might not work well in the WebUI.

Need a JavaScript version to run on the browser console: 1

Ameb commented 1 year ago

I did use the following code from the browser console.

let qbit_url=window.location.href
let old_url='https://oldurl.com'
let new_url='https://newurl.xyz'

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-trackers
var change_url = (torrent) => fetch(qbit_url + 'api/v2/torrents/editTracker?' + new URLSearchParams({
   hash: torrent.hash,
   origUrl: torrent.tracker,
   newUrl: torrent.tracker.replace(old_url, new_url)
}))

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-list
fetch(qbit_url + 'api/v2/torrents/info')
   .then(response => response.json())
   // Filter torrents with your url
   .then(torrents => torrents.filter(({tracker}) => tracker.startsWith(old_url)))
   // request change for each torrent
   .then(torrents => torrents.map(change_url))

In case the tracker url no longer works (tracker status 'Not Working') by qBittorrent: This version is probably slower, but I added some feddback to the console.

⚠️ The API torrent/removeTrackers doesn't work properly on 4.5 and will return ok (200) even when it didn't removed a tracker. This script is not safe if you have trackers from a different domain on qB 4.5

var PID = 'myPID'
var old_url = 'https://olddomain/announce/' + PID
var new_url = 'https://newdomain/announce/' + PID

var qbit_url = window.location.href

var recreate_tracker = (torrent) => fetch(qbit_url + 'api/v2/torrents/removeTrackers?' + new URLSearchParams({
    hash: torrent.hash,
    urls: old_url,
})).then((response) => response.status == 200 ? fetch(qbit_url + 'api/v2/torrents/addTrackers?', {
    "body": new URLSearchParams({
        hash: torrent.hash,
        urls: new_url,
    }),
    "method": "POST"
}).then(response.status == 200 ? console.log(`✔️ ${torrent.name}`) : console.log(`❌ ERROR: ${torrent.name}`)
) : console.log(`❗️ NOT MODIFIED: ${torrent.name}`))

// optionally, use tags to filter
// var tag = 'script'
// fetch(qbit_url + 'api/v2/torrents/info?tag=' + tag)
fetch(qbit_url + 'api/v2/torrents/info')
    .then(response => response.json())
    .then(torrents => torrents.map(recreate_tracker))
Mancuerna commented 1 year ago

I did use the following code from the browser console.

let qbit_url=window.location.href
let old_url='https://oldurl.com'
let new_url='https://newurl.xyz'

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-trackers
var change_url = (torrent) => fetch(qbit_url + 'api/v2/torrents/editTracker?' + new URLSearchParams({
   hash: torrent.hash,
   origUrl: torrent.tracker,
   newUrl: torrent.tracker.replace(old_url, new_url)
}))

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-list
fetch(qbit_url + 'api/v2/torrents/info')
   .then(response => response.json())
   // Filter torrents with your url
   .then(torrents => torrents.filter(({tracker}) => tracker.startsWith(old_url)))
   // request change for each torrent
   .then(torrents => torrents.map(change_url))

I see that you are a victim of Redbits domain change. Working perfectly. Thank you so much @Ameb .

Ameb commented 1 year ago

If the tracker url no longer works, qbittorrent doesn't return it on the torrents/info endpoint so i had to made a different script. Edited my previous message

jcassette commented 1 year ago

The simple way

var editTracker = (torrent) => fetch(
    'http://qbittorrent.example:8080/api/v2/torrents/editTracker',
    {
        body: new URLSearchParams({
            hash: torrent.hash,
            origUrl: 'http://old.tracker.example/xxxxx/announce',
            newUrl: 'http://new.tracker.example/xxxxx/announce'
        }),
        method: 'POST'
    }
)

fetch('http://qbittorrent.example:8080/api/v2/torrents/info')
    .then(response => response.json())
    .then(torrents => torrents.map(editTracker))

On v4.5.0, it works when the old tracker is offline, and it does not change other trackers

paulverbeke commented 1 year ago

works well ! thank you both @jcassette and @Ameb.

We really need a WebUI implementation. Hopeful that someone build that feature one day

Simpuhl commented 1 year ago

+1

flashlab commented 1 year ago

I did use the following code from the browser console.

let qbit_url=window.location.href
let old_url='https://oldurl.com'
let new_url='https://newurl.xyz'

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-trackers
var change_url = (torrent) => fetch(qbit_url + 'api/v2/torrents/editTracker?' + new URLSearchParams({
   hash: torrent.hash,
   origUrl: torrent.tracker,
   newUrl: torrent.tracker.replace(old_url, new_url)
}))

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-list
fetch(qbit_url + 'api/v2/torrents/info')
   .then(response => response.json())
   // Filter torrents with your url
   .then(torrents => torrents.filter(({tracker}) => tracker.startsWith(old_url)))
   // request change for each torrent
   .then(torrents => torrents.map(change_url))

If your qb version ≥ 4.4.4,POST method should be used.

let url_qbit = location.protocol + '//' + location.host;
let url_base = 'https://basedomain.com';
let str_old = 'wwww';
let str_new = 'mmmm';

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#edit-trackers
var change_url = (torrent) => fetch(url_qbit + '/api/v2/torrents/editTracker', {
  // POST must be used in ≥ v4.4.4 https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#general-information
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded;charset=utf-8;"
  },
  body: new URLSearchParams({
    hash: torrent.hash,
    origUrl: torrent.tracker,
    newUrl: torrent.tracker.replace(str_old, str_new)
  })
}).then(function(r) {
  console.log(torrent.hash + ': ' + r.status)
});

// Calls https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-list
fetch(url_qbit + '/api/v2/torrents/info')
  .then(response => response.json())
  // Filter torrents with your url
  .then(torrents => torrents.filter(({tracker}) => tracker.startsWith(url_base)))
  // request change for each torrent
  .then(torrents => torrents.map(change_url))
Schaka commented 3 months ago

For 4.6.0, this works:


var old_url = 'https://tracker.gg/announce/oldannounce'
var new_url = 'https://tracker.gg/announce/newannounce'
var tag = 'tag-to-filter'    
var qbit_url = window.location.href    
fetch(qbit_url + 'api/v2/torrents/info?tag='+tag)
    .then(response => response.json())
    .then(torrents => torrents?.map( response => {
        if(response.tags.indexOf(tag) != -1) {
            var deleteResponse = fetch(qbit_url + 'api/v2/torrents/editTracker?',
                {
                    "body": new URLSearchParams({
                        hash: response.hash,
                        origUrl: old_url,
                        newUrl: new_url
                    })
                    ,
                "method": "POST"
                 })
            console.log(deleteResponse)
            return deleteResponse     
        }
    }))

Without a tag to filter (will go over all your 1000s of torrents):

var qbit_url = window.location.href   

var old_url = 'https://tracker.cc/announce/old-pass-key'
var new_url = 'https://tracker.cc/announce/new-pass-key'

fetch(qbit_url + 'api/v2/torrents/info)
    .then(response => response.json())
    .then(torrents => torrents?.map( response => {
          var deleteResponse = fetch(qbit_url + 'api/v2/torrents/editTracker?',
              {
                  "body": new URLSearchParams({
                      hash: response.hash,
                      origUrl: old_url,
                      newUrl: new_url
                  })
                  ,
              "method": "POST"
               })
          console.log(deleteResponse)
          return deleteResponse
    }))

Untested, but should work for any "remote" instances that you're not currently logged into:

var qbit_url = 'http://qbit.url:8080/'
var username = 'username' 
var pw = 'password' 

var old_url = 'https://tracker.cc/announce/old-pass-key'
var new_url = 'https://tracker.cc/announce/new-pass-key'

// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#making_cross-origin_requests
fetch(qbit_url + 'api/v2/torrents/info)
    .then(response => response.json())
    .then(torrents => torrents?.map( response => {
        var headers = new Headers({
            'Authorization': `Basic ${btoa(username + ':' + pw)}`
        })
        var deleteResponse = fetch(qbit_url + 'api/v2/torrents/editTracker?',
            {
                "body": new URLSearchParams({
                    hash: response.hash,
                    origUrl: old_url,
                    newUrl: new_url
                }),
                "method": "POST",
                "headers": headers,
                "mode": 'no-cors'
                })
        console.log(deleteResponse)
        return deleteResponse     
    })
    )
HALlowe2000 commented 2 months ago

For 4.6.0, this works:


var old_url = 'https://tracker.gg/announce/oldannounce'
var new_url = 'https://tracker.gg/announce/newannounce'
var tag = 'tag-to-filter'    
var qbit_url = window.location.href    
fetch(qbit_url + 'api/v2/torrents/info?tag='+tag)
    .then(response => response.json())
    .then(torrents => torrents?.map( response => {
        if(response.tags.indexOf(tag) != -1) {
            var deleteResponse = fetch(qbit_url + 'api/v2/torrents/editTracker?',
                {
                    "body": new URLSearchParams({
                        hash: response.hash,
                        origUrl: old_url,
                        newUrl: new_url
                    })
                    ,
                "method": "POST"
                 })
            console.log(deleteResponse)
            return deleteResponse     
        }
    }))

Is there a version of this that will just let you add a new URL when one does not exist? Trying to recover from a crash, and adding the torrents back from a backup I'm seeing that for some reason the announce URL is missing. So I just need to be able to add it to all of them.

Schaka commented 2 months ago

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#add-trackers-to-torrent There's someone already using it here: https://github.com/qbittorrent/qBittorrent/issues/11868#issuecomment-1338173074

Replace editTracker with addTrackers Inside the body, remove origUrland newUrl, just use urls

HALlowe2000 commented 2 months ago

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#add-trackers-to-torrent There's someone already using it here: #11868 (comment)

Replace editTracker with addTrackers Inside the body, remove origUrland newUrl, just use urls

I tried this, but it gave me a 404 error for each:

var new_url = 'https://tracker.gg/announce/newannounce'
var tag = 'tag-to-filter'
var qbit_url = window.location.href
fetch(qbit_url + 'api/v2/torrents/info?tag='+tag)
    .then(response => response.json())
    .then(torrents => torrents?.map( response => {
        if(response.tags.indexOf(tag) != -1) {
            var deleteResponse = fetch(qbit_url + 'api/v2/torrents/addTracker?',
                {
                    "body": new URLSearchParams({
                        hash: response.hash,
                        urls: new_url
                    })
                    ,
                "method": "POST"
                 })
            console.log(deleteResponse)
            return deleteResponse     
        }
    }))
Piccirello commented 1 month ago

I'm having trouble following this thread since the image in the OP is broken. Could someone help me understand what the desired functionality is?

nickspacemonkey commented 1 month ago

If we have a bunch of torrents from a single tracker, and the tracker url changes. We would like a way to edit all selected torrent tracker urls, instead of doing it one by one. That’s lame when you gotta do it 1000 times or more.

Piccirello commented 1 month ago

I see, thank you. How do you achieve this today in the GUI? I was expecting an edit option in the Trackers filter menu, but I don't see one.

Screenshot 2024-10-14 at 23 57 21

Schaka commented 1 month ago

You simply don't. This is a feature request because it's not possible. You can only select single torrents and then edit their tracker URL.

You cannot select 1000 torrents and change the URL for all of them. That's why people are using Javascript snippets to query the API and do do exactly that, but from within the browser, logged into the web ui

Piccirello commented 1 month ago

The OP is describing a feature that's available in the GUI but not in the WebUI.

ooglyboogly commented 1 month ago

To clarify for everyone catching up. As seen by this Comment about this Commit for the GUI, you can see the picture evidence for what is being asked to be replicated in WebUI.