トレントを更新する別の方法

あるトラッカーでは、私は積極的な側近です。 しかし、ディストリビューションを更新するときが来ると、恐怖が始まります。トレントクライアントとトラッカーで名前が異なるディストリビューションもあります。トラッカーには同じ名前のディストリビューションがたくさんあり、特定のディストリビューションを検索するのは非常に困難です。 その上、私はそのような日常的なビジネスをする時間があまりありません。 そのため、トラッカーでディストリビューションを更新するときにクライアントのディストリビューションを更新する小さなスクリプトが必要でした。





どうする?



既成の解決策を見つけるか、自分で必要なスクリプトを作成するという課題に直面しました。 ハブには何らかの方法で私の仕事を果たす方法がありましたが、その方法は私に合わなかったか、まったく気に入らなかったのです。 同時に、私はプログラムもスクリプトも書いたことがないので、自分が書いたスクリプトのバージョンがさらに好きでした。 最初に、学習しやすくプログラミングに没頭できるツールであるツールを選択する必要があり、Pythonが注目を集めました。



私はすぐにPythonが好きでした。 それはコードを書くのにいくらかの「容易さ」を与えるようです。 最初のpythonリーダーとして、Mark Lutzの著書Learning Python(4th Edition)を選びました。 さて、ツールがあります、本の形で助けはありません、行きましょう!



問題のステートメントとその解決策



そのため、まずクライアントのトレントファイル(この場合はuTorrent 2.2を意味します)が古くなっていることを確認し、新しいファイルをダウンロードする必要があります。 最初に思いついたのは、ページを解析し、それらをtorrentファイル内のデータと比較することでした。 この方法は機能しましたが、速度に大きなマイナスがありました。100ページの解析、つまりトラッカーでの配信の制限などは約3分かかりました。 さらに、分布のすべてのパラメーターをページの解析結果と比較する必要があり、これにも多くの時間がかかりました。 この方法は失敗することなく機能しましたが、私は特に気に入らなかったので、問題に対するあらゆる種類の解決策を探し続けました。



すぐに、多くの熟考と検索の後に、私はそのようなことをひっかきました。 Wikipediaが言うように、Scrapeはトラッカーのための追加のクライアント要求プロトコルであり、トラッカーはクライアントにディストリビューション上のシードとピアの総数を伝えます。 スクレイプリクエストを使用すると、ディストリビューションが存在するかどうかを簡単に確認できます。 また、スクレイプ要求は、アナウンスよりも頻繁にクライアントによって送信されます。 ただし、特定のトラッカーがこのプロトコルをサポートしているかどうかを知る必要があります。 幸いなことに、私のトラッカーはそれをサポートしています。 スクレイプリクエストは、ヘッダー付きのGETメソッドを使用して送信されます。リクエストが送信されるアドレスは次のとおりです。

htt://example.com/scrape.php?info_hash=aaaaaaaaaaaaaaaaaaaa





ハッシュはディストリビューションごとに一意であり、20文字が含まれ、resume.datファイルから取得できます。 ただし、情報を取得する前に、拡張子が.torrentおよびsettings.datのファイルであるこのファイルがbencode形式で提示されていることを知っておく必要があります。 エンコード方式に深く入り込まずにファイルをすばやく復号化する必要がある場合は、 ここからpythonの特別なパッケージをダウンロードする必要があります。



ファイルを解読しましょう:



 # -*- coding: utf-8 -*- import urllib2 from urllib import urlencode from binascii import b2a_hex as bta, a2b_hex as atb from os import remove from shutil import move from lxml.html import document_fromstring as doc from bencode import bdecode, bencode from httplib2 Http http = Http() username = 'username' password = 'password' ut_port = '12345' #  web-  uTorrent'. ut_username = 'utusername' ut_password = 'utpassword' site = 'http://example.com/' scrape_body = site + 'scrape.php?info_hash=' # URL scrape-. login_url = site + 'takelogin.php' torrent_body = site + 'download.php?id={0}&name={0}.torrent' announce = site + 'announce.php?' # URL  . webui_url = 'http://127.0.0.1:{0}/gui/'.format(ut_port) webui_token = webui_url + 'token.html' #   .torrent .    settings.dat,  dir_torrent_files. torrent_path = 'c:/utorrent/torrent/' #      . autoload_path = 'c:/utorrent/autoload/' #     uTorrent'a (   resume.dat) sys_torrent_path = 'c:/users/myname/appdata/utorrent/' def authentication(username, password): data = {'username': username, 'password': password} headers = {'Content-type': 'application/x-www-form-urlencoded', 'User-agent':'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.6'} resp, login = http.request(login_url, 'POST', headers=headers, body=urlencode(data)) #   ,    cookiekeys = ['uid', 'pass', 'PHPSESSID', 'pass_hash', 'session_id'] split_resp = resp['set-cookie'].split(' ') lst = [] #          . for split_res in split_resp: if split_res.split('=')[0] in cookiekeys: lst.append(split_res) cookie = ' '.join(lst) return {'Cookie': cookie} def torrentDict(torr_path): #torr_path    -   resume.dat . Dict = {} with open(u'{0}resume.dat'.format(torr_path), 'rb') as resume: t = bdecode(resume.read()) for name in t: if name != '.fileguard' and name != 'rec': for tracker in t[name]['trackers']: if isinstance(tracker, str) and tracker.startswith(announce): Dict[name.split('\\')[-1]] = bta(t[name]['info']) return Dict
      
      





これで、ディストリビューションの名前とハッシュを含む辞書が手に入りました。 次に、置換および変更されたハッシュを使用してスクレイプリクエストを送信し、トラッカー上にそのようなハッシュを含む分布があるかどうか、またはすでに存在していないかどうかを確認する必要があります。 また、クライアントに代わってそのような要求を行う必要があることを忘れないでください。そうしないと、トラッカーはアクセスを拒否します。



 uthead = {'User-Agent':'uTorrent/2210(21304)'} #   uTorrent'. main_dict = torrentDict(sys_torrent_path) for key in main_dict: lst = [] for i in range(0, len(main_dict[key]), 2): lst.append('%{0}'.format(main_dict[key][i:i+2].upper())) scrp_str = ''.join(lst) # ,     . resp, scrp = http.request('{0}{1}'.format(scrape_body, scrp_str), 'GET', headers=uthead)
      
      







リクエストに対する典型的な応答は次のようになります。

d5:filesd20: aaaaaaaaaaaaaaaaaaaa d8:completei 5 e10:downloadedi 50 e10:incompletei 10 eeee



20文字の「a」は配布のハッシュ、5-サイド、10-リーチャー、50のダウンロードの完了です。

ディストリビューションが存在しない場合、リクエストへの応答は次の形式を取ります。

d5:filesdee





リクエストへの応答もベンコード形式で表示されますが、復号化する必要はありません。トラッカーにそのようなハッシュの分布がない場合、受信した文字列と返された文字列を比較するだけです。

次に、トラッカーからファイルをダウンロードし、クライアントのスタートアップフォルダーに配置し、可能であれば、クライアント自体の古いtorrentエントリを削除する必要があります。

そのようにトラッカーからファイルをダウンロードすることはできません。承認が必要です。 関数自体は、上記の「認証」という見出しの下で説明されています。 次に、ログインしてファイルをダウンロードし、スタートアップフォルダーに入れて、トレントのあるフォルダーから古い.torrentファイルを削除します。



  #        "for key in Dict:". with open('{0}{1}'.format(torrent_path, key), 'rb') as torrent_file: torrent = bdecode(torrent_file.read()) t_id = torrent['comment'][36:] #        . brhead = authentication(username, password) resp, torrent = http.request(torrent_body.format(t_id), headers=brhead) with open('{0}.torrent'.format(t_id),'wb') as torrent_file: torrent_file.write(torrent) #   .torrent       . remove('{0}{1}'.format(torrent_path, key)) move('{0}.torrent'.format(t_id), '{0}{1}.torrent'.format(autoload_path, t_id)) #     .   . authkey, token = uTWebUI(ut_username, ut_password) webuiActions(main_dict[key], 'remove', authkey, token)
      
      







既に存在しない.torrentファイルがクライアントのレコードと混同しないように、クライアントから削除する必要があります。 ただし、uTorrentは、resume.datを編集するように配置されており、クライアントの実行中にすべてのトレントに関する情報が保存されると、結果が得られません。 したがって、この場合、uTorrentを常にオフにし、resume.datを編集し、uTorrentをオンにする必要があります。 このような方法は、1日に1つの変更された配布に適していますが、配布がバッチで変更された場合、つまり 一度にいくつか? 最初は、一般的なプログラミングとはかけ離れていたため、プロセスを直接操作する必要があると思いましたが、これは私にとって非常に困難です。 しかし、その後、uTorrent WebUIの存在を知りました。 WebUIにはAPIがあり、そのドキュメントは公式Webサイトにあります。 WebUI APIの機能のおかげで、クライアントからのトレントに関するレコードを削除できるだけでなく、削除することもできます。 まず、特別なパスワードとトークンを持つCookieを取得する必要があります。 クライアントのwebui.token_authパラメーターがアクティブになっている場合、2番目が必要です。



 def uTWebUI(ut_name, ut_passw): #  cookie  token. passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() passmgr.add_password(None, webui_token, ut_name, ut_passw) authhandler = urllib2.HTTPBasicAuthHandler(passmgr) opener = urllib2.build_opener(authhandler) urllib2.install_opener(opener) req = urllib2.Request(webui_token) tkp = urllib2.urlopen(req) page = tkp.read() token = doc(page).xpath('//text()')[0] passw = req.unredirected_hdrs['Authorization'] return passw, token def webuiActions(torrent_hash, action, password, token): head = {'Authorization': password} if action == 'remove': #       . action_req = '?token={0}&action=remove&hash={1}'.format(token, torrent_hash) r, act = http.request(webui_url+action_req, headers=head)
      
      







uTorrentでは、Webインターフェイスでの承認はサイトとは異なる方法で実装されるため、データの単純な送信は機能しません。 次に、トークンを取得し、それと一緒にクライアントで何らかの機能を実行します。 もちろん、クライアントのアクションにクラスを割り当てることは可能ですが、これには通常の機能で十分であると考えました。

(注:残念ながら、現時点での私の知識はWebインターフェースに正しくログインするには不十分であるため、インターネットで説明されている方法を使用しました。)



結果は何ですか



その結果、私は自分のニーズを満たし、少しの知識と多くの喜びを満たすスクリプトを手に入れました。朝までコードの上に座ってから、寝るときにキャッチとは何かを理解するのはとても楽しいです。



この方法が誰かを助けることを願っています。



UPD:不注意で大いに謝ります:コードを公開する前により読みやすい形式にしたので、その結果、私自身が混乱し、あなたが混乱しました。

コードはGithubにアップロードされます。 私は彼と初めて仕事をしているので、何か間違ったことをしたら、連絡してください。



All Articles