Sida 1 av 2

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:53
av Konservburk

1. Inledning


Inställningsmöjligheterna i rtorrent är egentligen ingen hemlighet även om informationen av någon anledning tycks vara höljd i dunkel. Det går faktiskt att få till betydligt mer sofistikerade och avancerade lösningar i ~/.rtorrent.rc än vad manualbladet ger sken av.

Här tänker jag ta upp sådant som egentligen inte finns ordentligt dokumenterat, varken i manualbladet eller på rtorrents wiki-sidor. Jag har istället studerat källkoden till rtorrent-0.8.4 för att ta reda på hur det hela hänger ihop. Förmodligen gäller mycket av detta även andra versioner, men det är långt ifrån säkert.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:53
av Konservburk

2. Grundläggande syntax


Varje enskild rad i ~/.rtorrent.rc är ett helt eget separat rtorrent-kommando. Dessa inleds alltid med själva kommandonamnet följt av ett likhetstecken och därefter en argumentlista med noll eller flera kommaseparerade argument.

Kod: Markera allt

kommando_namn = argument_0, argument_1, argument_2, argument_3
Vad som i en vanlig ~/.rtorrent.rc ser ut att vara enkla tilldelningar är egentligen inget annat än rtorrent-kommandon med ett enda argument.

Det mest komplicerade kommandot som vanligtvis används är schedule som tar exakt fyra argument där det fjärde inte är något mindre än ett fullständigt rtorrent-kommando med en helt egen argumentlista. Här uppstår genast problemet att rtorrent måste kunna förstå vilka argument som hör till vilken argumentlista. Detta innebär att det inre kommandot måste escape:as på ett eller annat sätt. Det är nu det börjar bli intressant.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:53
av Konservburk

3. Fnuttologi


För att detta inte ska bli alltför förvirrande så inför jag begreppet escape-nivåer, där nivå-A är kommandon som inte behöver escape:as, nivå-B kommandon som behöver escape:as en gång, osv.

I en vanlig simpel ~/.rtorrent.rc är det mesta nivå-A och en del nivå-B. I undantagsfall förekommer även nivå-C, men i princip aldrig djupare än så. Här kommer vi dock att nosa oss ända in till som mest nivå-G.

Den grundläggande escape-varianten är att sätta ett backslash framför varje enskilt tecken som rtorrent tolkar som något annat än som en del av en sträng. Det stora problemet är även backslash måste escape:as på detta sätt, vilket medför att antalet backslash-tecken som behövs växer exponentiellt med escape-nivån. I nivå-C behövs t.ex. tre backslash för varje tecken som ska escape:as. Det första escape:ar det andra som i sin tur följer med ut en nivå, och det tredje escape:ar själva tecknet som egentligen skulle escape:as. Den exakta formeln för antalet backslash som behövs är 2^(escape-nivån)-1:
  • A: 2^0 - 1 = 0
    B: 2^1 - 1 = 1
    C: 2^2 - 1 = 3
    D: 2^3 - 1 = 7
    E: 2^4 - 1 = 15
    F: 2^5 - 1 = 31
    G: 2^6 - 1 = 63
En alternativ metod är att omge hela nivå-B med dubbelfnuttar. Ska även nivå-C escape:as på detta sätt så måste dubbelfnuttarna i sig escape:as med backslash, vilket innebär att vi egentligen bara har skjutit upp problemet en nivå. Å andra sidan så kan två escape:ade dubbelfnuttar i sig escape:a många andra tecken.

Nu har det blivit läge för ett illustrerande exempel. I följande o-escape:ade rtorrent-kommando indikeras den önskade nivån av bokstäverna och argumentnumren av siffrorna:

Kod: Markera allt

A = a0, B = b0, C = c0, c1, D = d0, d1, d2, d3, c3, b2, a2
De två olika sätten att escape:a kommandot på blir som följer:

Kod: Markera allt

A=a0,B=b0\,C=c0\\\,c1\\\,D=d0\\\\\\\,d1\\\\\\\,d2\\\\\\\,d3\\\,c3\,b2,a2

Kod: Markera allt

A = a0, "B = b0, \"C = c0, c1, \\\"D = d0, d1, d2, d3\\\", c3\", b2", a2
Eftersom även mellanrummen måste escape:as så har jag skippat dem helt i den rena backslash-metoden. De behövs egentligen inte. Fördelen med fnutt-metoden är att de blir escape:ade på köpet och därför kan få vara kvar för att öka läsligheten.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:53
av Konservburk

4. Fördjupad fnuttologi


Vilken escape-metod som resulterar i flest backslash och därför bör undvikas varierar helt beroende på hur kommandot ser ut, nivån och antalet argument. För nivå-B är det ganska likvärdigt oavsett argumentantalet:

Kod: Markera allt

B=
B=b0
B=b0\,b1
B=b0\,b1\,b2
B=b0\,b1\,b2\,b3

Kod: Markera allt

"B ="
"B = b0"
"B = b0, b1"
"B = b0, b1, b2"
"B = b0, b1, b2, b3"
Jämför det med nivå-E där den rena backslash-metoden är klart bättre för kommandon med få argument, men klart sämre för kommandon med många argument:

Kod: Markera allt

E=
E=e0
E=e0\\\\\\\\\\\\\\\,e1
E=e0\\\\\\\\\\\\\\\,e1\\\\\\\\\\\\\\\,e2
E=e0\\\\\\\\\\\\\\\,e1\\\\\\\\\\\\\\\,e2\\\\\\\\\\\\\\\,e3

Kod: Markera allt

\\\\\\\"E =\\\\\\\"
\\\\\\\"E = e0\\\\\\\"
\\\\\\\"E = e0, e1\\\\\\\"
\\\\\\\"E = e0, e1, e2\\\\\\\"
\\\\\\\"E = e0, e1, e2, e3\\\\\\\"
Generellt så är fnutt-metoden alltid sämre när det gäller kommandon med färre än två argument. På samma sätt är den rena backslash-metoden alltid sämre för kommandon med fler än två argument. Den trenden blir tydligare och tydligare ju djupare nivå man kommer till. Ta nivå-G som ett sista avskräckande exempel:

Kod: Markera allt

G=
G=g0
G=g0\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\,g1

Kod: Markera allt

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"G =\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"G = g0\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"G = g0, g1\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:54
av Konservburk

5. Övrig syntax


Det finns egentligen bara ytterligare en viktig sak att känna till. I vanliga fall skickas den inre nivån vidare som en oförändrad sträng till den yttre nivåns argument. Det är sedan upp till det yttre kommandot att avgöra om strängen ska tolkas som ett rtorrent-kommando som ska köras eller som en helt vanlig sträng. Det finns dock ett viktigt undantag. Om det absolut första tecknet i strängen som utgör en nivå är ett dollartecken så kommer nivån alltid att köras som ett kommando och det blir istället resultatet av det kommandot som skickas vidare till den yttre nivåns argument.

Kommandon kan dessutom separeras med semikolon och grupperas med krullparanteser. Det fungerar dock inte överallt, vilket egentligen inte är något problem eftersom det i princip aldrig varken är nödvändigt att kunna separera eller gruppera kommandon.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:54
av Konservburk

6. Att definiera egna rtorrent-kommandon


Det ännu odokumenterade rtorrent-kommandot system.method.insert används för att skapa helt egna rtorrent-kommandon. Det första argumentet anger kommando-namnet som man kan välja helt själv. Det andra argumentet avgör vilken typ av kommando det rör sig om. Det finns flera olika varianter, men de mest intressanta är value och const_simple.

Kod: Markera allt

system.method.insert = return , value
Detta skapar ett kommando av typen value med namnet return som inte tar några argument. I samma veva skapas även kommandot return.set som tar ett argument och kan användas för att sätta värdet som returneras av return. Inte speciellt spännande, men mycket användbart.

Nu tar vi istället en närmare titt på typen const_simple. De resterande argumenten är fullständiga rtorrent-kommandon som körs när det egenvalda kommandonamnet anropas.

Kod: Markera allt

system.method.insert = \
   d.stop_and_close \
,  const_simple \
,  d.stop= \
,  d.set_ignore_commands=1 \
,  d.close=
Här har jag döpt mitt kommando till d.stop_and_close, som i tur och ordning kommer att anropa rtorrent-kommandona d.stop=, d.set_ignore_commands=1 och d.close=, vilket är samma sak som händer när man trycker ctrl-k. Det inledande "d." indikerar att kommandot bara kan köras om det är associerat med en faktiskt torrent. På samma sätt måste kommandon som börjar med "f." vara associerade med en faktisk fil, kommandon som börjar med "t." med en tracker och "p." med en peer. Exakt hur man associerar kommandon med faktiska torrenter, filer, trackers, och peers tar jag upp senare.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:54
av Konservburk

7. Villkor och argument


Ett av de för oss mest användbara rtorrent-kommandona är branch, vars första argument är ett villkor som avgör om det andra eller tredje argumentet ska köras. Finns det fler än tre argument så avgör det tredje argumentet om det fjärde eller femte ska köras, osv. Men för att verkligen kunna få till riktigt användbara villkor så vill man först kunna ta reda på vilka argument som det egna kommandot har tagit emot. För att göra det så använder man sig av rtorrent-kommandona argument.0, argument.1 osv. Det kan se ut ungefär så här:

Kod: Markera allt

system.method.insert = \
   try_run_arg \
,  const_simple \
,  "  branch = \
         \" \
            or = \
               \\\" \
                  less = \
                     argument.0= \
                  ,  cat=placeholder \
               \\\" \
            ,  \\\" \
                  less = \
                     cat=placeholder \
                  ,  argument.0= \
               \\\" \
         \" \
      ,  $argument.0= \
   "
Det går ut på att jag vill köra det första argumentet bara om det inte råkar vara lika med strängen placeholder, som är standardvärdet för osatta argument. Ett lustigt sätt att få till ett likhetstest kan tyckas, men det är så man får göra när det inte finns annat än or och less att tillgå. Eftersom kommandot less förväntar sig att argumenten i sig är kommandon så måste vi använda oss av kommandot cat för att kunna få med placeholder som en sträng. Det är även därför som argument.0 saknar ett inledande dollartecken när det är argument till just less.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:54
av Konservburk

8. Returvärden


För att kunna få tillbaka returvärden kan vi använda oss av return som vi redan skapat tidigare. Men för att det inte ska bli så mycket strul varje gång det behövs ett returvärde så ordnar vi ett separat kommando som hanterar den biten:

Kod: Markera allt

system.method.insert = \
   evaluate \
,  const_simple \
,  "  branch = \
         $argument.1= \
      ,  return.set=false \
      ,  return.set=true \
   " \
,  "  branch = \
         $argument.0= \
      ,  return.set=$not=$return= \
   " \
,  "  branch = \
         return= \
      ,  try_run_arg=$argument.2= \
      ,  try_run_arg=$argument.3= \
   "
Här avgör argument.1 om returvärdet blir sant eller falskt, medan argument.0 avgör om returvärdet ska vara inverterat eller inte, vilket bara är en bekvämlighetsgrej för att slippa använda kommandot not när vårt nya kommando evaluate anropas och på så sätt kunna undvika en extra escape-nivå. Returvärdet får tillslut avgöra om argument.2 eller argument.3 ska köras. Eftersom det inte är säkert att något av dessa argument ens har blivit satta så får vi nu användning för vårt tidigare kommando try_run_arg.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:55
av Konservburk

9. Wrapper-kommandon


Det har blivit dags att börja dra lite nytta av alla mödor med evaluate-kommandot. Först ett relativt enkelt wrapper-kommando runt kommandot less, vilket egentligen inte är något märkvärdigare än att slå in less-kommandot i lite kod som ser till så att less alltid får vettig indata och ger vettig utdata tillbaka.

Kod: Markera allt

system.method.insert = \
   require \
,  const_simple \
,  "  branch = \
         not=$argument.1= \
      ,  require=0\\\,0 \
      ,  not=$argument.0= \
      ,  require=0 \
      ,  \" \
            evaluate = \
            ,  \\\"$ \
                  less = \
                     return.set=$argument.0= \
                  ,  return.set=$argument.1= \
               \\\" \
         \" \
   "
Egentligen inga konstigheter. Först sätts standardvärden för argument.1 och argument.0 om de skulle råka var tomma. Sedan jämförs argumenten med varandra och eftersom vi har ett inledande dollartecken så skickas resultatet av snarare än hela less-kommandot vidare till evaluate-kommandot. En slamkrypare är att return.set i det här fallet inte har någonting med returvärdet att göra. Den biten hanteras ju av evaluate som på grund av dollartecknet ens kommer att se return.set. Det är istället så att return.set i det här fallet är ett smart sätt att tvinga fram en konvertering från sträng till tal, vilket innebär att det går att anropa det nya require-kommandot på ett betydligt smidigare sätt än vad som annars skulle ha varit möjligt.

Nu går det t.ex. att köra require=$d.get_ratio=,1000,d.close= för att stänga en torrent om den har en ratio på minst 1. Och nu tänker du genast att det ju redan finns speciella kommandon för att göra just det. Det stämmer bra, men det här är betydligt smidigare eftersom vi även kan anropa require med andra argument än d.get_ratio och d.close utan några svårigheter.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:55
av Konservburk

10. Externa villkor


Nu har vi kommit fram till en punkt där rtorrents interna kommandon inte längre räcker till för det jag vill åstadkomma. I det här fallet handlar det om sträng-matchning, vilket kan vara mycket användbart, men som sagt kräver ett externt kommando:

Kod: Markera allt

system.method.insert = \
   match \
,  const_simple \
,  "  evaluate = \
      ,  \"$   execute_raw_nothrow = \
                  sh \
               ,  -c \
               ,  \\\" \
                     printf %s \\\\\\\"$0\\\\\\\" | \
                     grep -qE \\\\\\\"$1\\\\\\\" \
                  \\\" \
               ,  $argument.0= \
               ,  $argument.1= \
         \" \
   "
Det externa kommando som har används är inget annat än en omskrivning av det enkla skriptet:

Kod: Markera allt

#!/bin/sh
printf %s "$0" | grep -qE "$1"
Jag hade i princip kunnat använda vilket matchningskommando som helst, t.ex. awk, sed, perl eller varför inte expr. Men nu blev det grep den här gången.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:55
av Konservburk

11. En första tillämpning


Nu har vi kommit fram till ett läge där det faktiskt går att få till något som är fullt användbart. Tanken är att använda det nya match-kommandot för att testa om om en ny torrent hör till en viss speciell tracker, och utifrån den informationen sätta vilken katalog torrenten sedan laddas ner till.

Kommandot för att ta reda på tracker-adresssen är t.get_url, vilket som tidigare nämnts kräver att kommandot associeras med en tracker. För att lyckas med det använder vi oss av kommandot t.multicall som kör kommandon associerade med var och varje tracker för en given torrent.

Kod: Markera allt

system.method.insert = \
   d.match_tracker \
,  const_simple \
,  "  match = \
         \"$   t.multicall = \
               ,  t.get_url= \
         \" \
      ,  $argument.0= \
      ,  $argument.1= \
      ,  $argument.2= \
   "
Här skickas de olika argumenten helt enkelt bara vidare till match utan några konstigheter. Svårare än så här blev det faktiskt inte. Nu gäller det bara att koppla vårt nya d.match_tracker-kommando så att det körs för varje ny torrent som laddas in. För att lyckas med det använder vi oss av kommandot system.method.set_key med argumentet event.download.inserted_new, vilket talar om att vi vill göra någonting just när en ny torrent laddas in:

Kod: Markera allt

system.method.set_key = event.download.inserted_new , filter_ubuntu \
,  "  d.match_tracker = (torrent\\\\\\\.ubuntu\\\\\\\.com) \
      ,  d.set_directory_base=/media/linux-images/ \
   "
Här sätts nerladdningskatalogen till /media/linux-images/ om tracker-namnet innehåller torrent.ubuntu.com, men inte annars. Punkterna behöver egentligen inte escape:as eftersom de matchar vilket tecken som helst, t.ex. en punkt. Men jag tog ändå med dem för att visa hur många backslash det egentligen ska vara.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:55
av Konservburk

12. Mer avancerade villkor


Det har blivit dags att använda match-kommandot till sin fulla potential. Låt oss börja med ett kommando som vi kallar d.require_seeds där vi helt enkelt kräver att torrenten har ett visst antal seeders samt att antalet seeders är minst lika stort som antalet leechers. Vi använder oss även denna gång av t.multicall-kommandot, samt return.set för att konvertera sträng till tal.

Kod: Markera allt

system.method.insert = \
   d.require_seeds \
,  const_simple \
,  "  match = \
         \"$   t.multicall = \
               ,  \\\" \
                     or = \
                        \\\\\\\" \
                           less = \
                              t.get_scrape_complete= \
                           ,  t.get_scrape_incomplete= \
                        \\\\\\\" \
                     ,  \\\\\\\" \
                           less = \
                              t.get_scrape_complete= \
                           ,  return.set=$argument.0= \
                        \\\\\\\" \
                  \\\" \
         \" \
      ,  0 \
      ,  $argument.1= \
      ,  $argument.2= \
   "
Efersom t.multicall kör villkoret för alla trackers som hör ihop med torrenten, så kan det bli fler än ett resultat. Tricket här är att matcha mot något av dem, dvs ett slags any-kommando. Hur man gör för att få till ett all-kommando där alla villkor måste stämma illustrerar jag med ytterligare ett användbart exempel. Den här gången vill jag ta reda på om en torrent är färdignerladdad med hänsyn tagen till det faktum att man faktiskt kan välja bort delar av en torrent som man inte är intresserad av.

Kod: Markera allt

system.method.insert = \
   d.completed \
,  const_simple \
,  "  match = \
         \"$   f.multicall = \
               ,  \\\" \
                     and = \
                        f.get_priority= \
                     ,  \\\\\\\" \
                           less = \
                              f.get_completed_chunks= \
                           ,  f.get_size_chunks= \
                        \\\\\\\" \
                  \\\" \
         \" \
      ,  1 \
      , \
      , \
   " \
,  "  evaluate = \
      ,  $return= \
      ,  $argument.0= \
      ,  $argument.1= \
   " \
Den här gången använde jag f.multicall och undersöker ifall varje fil är antingen helt nerladdad eller har en prioritet som är satt till off. Själva matchningen är egentligen sig helt lik, fast omvänd. Jag matchar mot att någon av filerna inte är klar. För att sedan åter igen vända på steken och få till all-villkoret så använder jag mig av vårt evaluate-kommando på returvärdet. Kanske inte helt uppenbart, men det fungerar bra.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:56
av Konservburk

13. Köra kommandon på flera olika torrents


Vi har redan tidigare använt oss av kommandona t.multicall och f.multicall för att kunna köra tracker- respektive fil-associerade kommandon för flera trackers och filer på en gång. Motsvarande kommando för torrents är d.multicall, men eftersom varje torrent har en individuell inställning som indikerar om torrenten i fråga verkligen vill lyda kommandon eller inte så vill vi inte köra d.multicall rakt av utan att ta hänsyn till just detta.

Kod: Markera allt

system.method.insert = \
   select_heed \
,  const_simple \
,  "  d.multicall = \
         $argument.0= \
      ,  \" \
            branch = \
               d.get_ignore_commands= \
            ,  return.set=false \
            ,  \\\" \
                  evaluate = \
                     not= \
                  ,  \\\\\\\"$ \
                        branch = \
                           argument.1= \
                        ,  argument.1= \
                        ,  not= \
                     \\\\\\\" \
               \\\" \
         \" \
   "
Den första argumentet till d.multicall avgör för vilken grupp av torrenter det följande kommandot ska gälla. Om man inte anger något speciellt så blir det alla, men man skulle t.ex. kunna nöja sig med bara de som är startade. Här är vi dock generella och skickar vidare just det argumentet. Att jag använder ett branch-kommando i evaluate-kommandot istället för argument.1 direkt har att göra med hur jag vill att ett tomt argument.1 ska bete sig.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:56
av Konservburk

14. Faktisk användning av det vi hittills gjort


Tanken är att få till ett kommando som stänger färdiga torrenter så fort de får minst 1 i ratio, men bara om det finns minst lika många seeders som leechers och minst 3 seeders. Vi vill däremot inte att torrenter som är satta till ignore_commands ska stängas av, varför det nya select_heed-kommandot nu kommer väl till pass. Här räcker det dock inte med att skicka med resultatet av vårt förutsatta kombinerade villkor. Anledningen är att testet måste utföras för varje torrent som d.multicall väljer ut. Det är egentligen inte mer komplicerat än vad vi gjort innan, men det kräver fler escape-nivåer, och vi kommer få nytta av den inledande fnuttologin:

Kod: Markera allt

system.method.insert = \
   completed_dual_filter \
,  const_simple \
,  "  select_heed = \
         $argument.0= \
      ,  \"$   cat = \
                  \\\" \
                     and = \
                        \\\\\\\" \
                           return = \
                              \\\\\\\\\\\\\\\"$ \
                  \\\" \
               ,  $argument.1= \
               ,  \\\" \
                                 , \
                                 , \
                              \\\\\\\\\\\\\\\" \
                        \\\\\\\" \
                     ,  \\\\\\\" \
                           return = \
                              \\\\\\\\\\\\\\\"$ \
                  \\\" \
               ,  $argument.2= \
               ,  \\\" \
                                 , \
                                 , \
                              \\\\\\\\\\\\\\\" \
                        \\\\\\\" \
                     ,  \\\\\\\" \
                           return = \
                              \\\\\\\\\\\\\\\"$ \
                                 d.completed = \
                                 , \
                              \\\\\\\\\\\\\\\" \
                        \\\\\\\" \
                  \\\" \
         \" \
      ,  $argument.3= \
      ,  \
   "
Av de tre villkoren valde jag att bara hårdkoda d.completed, och istället skicka med de andra som argument. Anledningen är att vi då kan återanvända kommandot till annat senare. Det blir en förhållandevis enkelt kommando för att faktiskt skicka med de båda extra villkoren.

Kod: Markera allt

system.method.insert = \
   on_ratio_and_seeds \
,  const_simple \
,  "  completed_dual_filter = \
         $argument.0= \
      ,  \"$   cat = \
                  require=$d.get_ratio= \
               ,  \\\\\\\, \
               ,  $argument.1= \
         \" \
      ,  \"$   cat = \
                  d.require_seeds= \
               ,  $argument.2= \
         \" \
   "
Nu är det bara kvar att binda vårt nya mästerverk med schedule-kommandot så att det körs med jämna mellanrum:

Kod: Markera allt

schedule = close_on_ratio_and_seeds , 10 , 60 \
,  "  on_ratio_and_seeds = \
         started \
      ,  1000 \
      ,  3 \
      ,  d.stop_and_close= \
   "

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:56
av Konservburk

15. Räkneoperationer


Det finns inget inbyggt kommando som kan räkna så vi behöver precis som med match-kommandot använda oss av extern hjälp. Den här gången blir det dock betydligt mer komplicerat eftersom vi faktiskt vill kunna ta till var på resultatet och inte bara göra ett simpelt test. Jag har valt att använda mig av ett filrör, en så kallad fifo. Det är ett utmärkt tillfälle att introducera ytterligare en kommando-typ, nämligen static_const_string. Eftersom den är static_const så måste vi initiera värdet direkt när vi deklarerar den genom det tredje argumentet.

Kod: Markera allt

system.method.insert = fifo , static_const_string \
,  "$ cat = /var/run/rtorrent. , $system.pid= , .fifo"
Jag har valt att använda awk för att utföra själva beräkningarna. Det är åter igen ett godtyckligt val från min sida som i princip kan ersättas med vilket annat kommando som helst som klarar av att räkna. För att läsa av fifo:n och få tillbaka returvärdet så använder jag rtorrent-kommandot import.

Kod: Markera allt

system.method.insert = \
   arithmetic \
,  const_simple \
,  "  execute_raw_nothrow = \
         sh \
      ,  -c \
      ,  \"$   cat = \
                  \\\" \
                     mkfifo \\\\\\\"$0\\\\\\\"; \
                     echo return.set= | awk '{print$0( \
                  \\\" \
               ,  $argument.0= \
               ,  \\\" \
                     )}' >\\\\\\\"$0\\\\\\\" && \
                     rm -f \\\\\\\"$0\\\\\\\" & \
                  \\\" \
         \" \
      ,  $fifo= \
   " \
,  import=$fifo=
Jag valde att göra det egentliga räknekommandot väldigt generellt så att det blir lätt att lägga till flera olika räknekommandon om det skulle visa sig behövas. För tillfället nöjer vi oss med ett enkelt kommando som räknar ut skillnaden mellan två olika värden.

Kod: Markera allt

system.method.insert = \
   diff \
,  const_simple \
,  "  arithmetic = \
         \"$   cat = \
                  $argument.0= \
               ,  - \
               ,  $argument.1= \
         \" \
   "

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:56
av Konservburk

16. Hålla reda på hur länge varje torrent seedats


Att ta reda på hur länge en torrent faktiskt har seedat är ett delikat problem, speciellt om datorn inte är igång dygnet runt. Nu ska vi försöka göra saken betydligt enklare genom att registrera den verkliga seed-tiden. Jag väljer att använda kommandona d.set_custom5 och d.get_custom5 för att hålla reda på värdet som måste uppdateras varje gång torrenten stoppas eller startas. För att göra det hela någorlunda hanterbart så skapar vi ett kommando som har hand om den saken.

Kod: Markera allt

system.method.insert = \
   d.register_seed_time \
,  const_simple \
,  "  branch = \
         d.get_custom5= \
      ,  \" \
            d.set_custom5 = \
               \\\"$ \
                  cat = \
                     \\\\\\\"$ \
                        return = \
                           \\\\\\\\\\\\\\\"$ \
                              diff = \
                                 $system.time= \
                              ,  $d.get_custom5= \
                           \\\\\\\\\\\\\\\" \
                     \\\\\\\" \
               \\\" \
         \" \
      ,  d.is_active= \
      ,  d.set_custom5=$cat=$system.time= \
   " \
,  "  require = \
         $d.get_custom5= \
      ,  $argument.0= \
      , \
      ,  \"$   cat = \
                  d.set_custom5= \
               ,  $argument.0= \
         \" \
   " \
,  "  d.completed = \
      ,  d.set_custom5= \
   "
Det kanske inte är helt uppenbart varför d.register_seed_time-kommandot ser ut som det gör. Logiken bakom är hur som helst att seed-tiden uppdateras om den redan finns registrerad, i annat fall nollställs den. Sedan görs en kontroll med vårt egna require-kommando så att seed-tiden verkligen uppdaterades åt rätt håll, annars återställs det tidigare värdet. Kontrollen behövs för de fall när rtorrent inte avslutats korrekt så att seed-tiden aldrig uppdaterades när torrenten stängdes. Slutligen görs en kontroll så att torrenten verkligen är klar, i annat fall avregistreras seed-tiden helt. Nu behöver vi bara koppla kommandot till några lämpliga händelser.

Kod: Markera allt

schedule = monitor_seed_time , 60 , 60 \
,  "  d.multicall = incomplete , d.register_seed_time=$d.get_custom5=  "

Kod: Markera allt

system.method.set_key = event.download.finished , initialize_seed_time \
,  d.register_seed_time=$system.time=

Kod: Markera allt

system.method.set_key = event.download.paused , save_seed_time \
,  d.register_seed_time=

Kod: Markera allt

system.method.set_key = event.download.resumed , restore_seed_time \
,  d.register_seed_time=$d.get_custom5=
Jag väljer att köra en uppdatering i minuten, samt en när torrenten startas och en när den stoppas. Dessutom nollställs seed-tiden precis när en torrenten faktiskt blir klar.

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:57
av Konservburk

17. Ytterligare en faktiskt användning av det vi hittills gjort


Det är åter igen dags att få till något mer direkt användbart. Men först behöver vi ett kommando som plockar fram seed-tiden vi redan har registrerat. Exakt hur vi får fram den avgörs av om torrenten är startad eller stoppad. I övrigt ska det inte vara några konstigeheter alls.

Kod: Markera allt

system.method.insert = \
   d.get_seed_time \
,  const_simple \
,  "  branch = \
         not=$d.get_custom5= \
      ,  return.set=0 \
      ,  d.is_active= \
      ,  \" \
            diff = \
               $system.time= \
               ,  $d.get_custom5= \
         \" \
      ,  return.set=$d.get_custom5= \
   "
Nu får vi tillslut användning för att vi bara hårdkodade d.completed i det kombinerade testet tidigare. Det betyder att vi nu kan skapa ett nytt kombinerat test väldigt enkelt, men med andra villkor, nämligen en minsta seed-tid och en speciell tracker. Här får vi åter igen användning för vårt require-kommando.

Kod: Markera allt

system.method.insert = \
   on_tracker_and_time \
,  const_simple \
,  "  completed_dual_filter = \
         $argument.0= \
      ,  \"$   cat = \
                  d.match_tracker= \
               ,  $argument.1= \
         \" \
      ,  \"$   cat = \
                  require=$return=$d.get_seed_time= \
               ,  \\\\\\\, \
               ,  $argument.2= \
         \" \
   "
Slutligen är det bara kvar att koppla det hela till ett schedule-kommando. Jag väljer som exempel att alla torrents från thepiratebay.org ska kontrolleras var tionde minut och stoppas om de har seedats i mer än 1 miljon sekunder. Åter igen är backslasharna innan punkten inte nödvändiga, men är där för att visa hur många de faktiskt ska vara.

Kod: Markera allt

schedule = close_on_tracker_and_time , 600 , 600 \
,  "  on_tracker_and_time = \
         started \
      ,  thepiratebay\\\\\\\\\\\\\\\\.org \
      ,  1000000 \
      ,  d.stop_and_close= \
   "

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:57
av Konservburk

rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:57
av Konservburk

19. Efterord


Det här var egentligen tänkt som en julkalender, men jag fick aldrig riktigt tid att avsluta den helt. I de sista delarna skulle jag ha tagit upp lite om hur torrent-grupper fungerar. Vi får se om jag får tid och inspiration att fylla på med den biten senare.

Re: rTorrent: En avancerad djupgående guide till ~/.rtorrent.rc

Postat: 31 dec 2008, 15:57
av Konservburk
Finns det förresten någon som har lite kul ideér om vad man skulle kunna göra i ~/.rtorrent.rc?