├── .gitignore ├── README.md ├── bencoding.py ├── seedmage.py ├── torrent.py ├── torrent └── PLACE_TORRENT_FILE_HERE └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | .torrent 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fake Seeder 2 | 3 | ------ 4 | 5 | How to... 6 | 7 | 1. Put the seeds(.torrent files) in the torrent directory! 8 | 2. Modify the User-Agent and peer_id prefixes for torrents.py. 9 | 3. Install the appropriate library via `pip3 install requests`. 10 | 4. Exec `python3 seedmage.py` 11 | 12 | How to get UA and peer_id, please refer to [my website][1]. 13 | 14 | 15 | [1]: https://www.taterli.com "my website" 16 | -------------------------------------------------------------------------------- /bencoding.py: -------------------------------------------------------------------------------- 1 | """Helper methods to encode and decode Bencoding data.""" 2 | 3 | def _decode(raw_buffer, elements, index=0): 4 | if raw_buffer[index] == ord('d'): 5 | index += 1 6 | obj = {} 7 | while raw_buffer[index] != ord('e'): 8 | key = [] 9 | value = [] 10 | index = _decode(raw_buffer, key, index) 11 | index = _decode(raw_buffer, value, index) 12 | obj[key[0]] = value[0] 13 | index += 1 14 | elements.append(obj) 15 | elif raw_buffer[index] == ord('l'): 16 | index += 1 17 | list_elements = [] 18 | while raw_buffer[index] != ord('e'): 19 | value = [] 20 | index = _decode(raw_buffer, value, index) 21 | list_elements.append(value[0]) 22 | index += 1 23 | elements.append(list_elements) 24 | elif raw_buffer[index] == ord('i'): 25 | index += 1 26 | pos = index + raw_buffer[index:].find(ord('e')) 27 | number = int(raw_buffer[index:pos]) 28 | index = pos+1 29 | elements.append(number) 30 | else: 31 | pos = index + raw_buffer[index:].find(ord(':')) 32 | size = int(raw_buffer[index:pos]) 33 | index = pos+1 34 | data = raw_buffer[index:index+size] 35 | index += size 36 | elements.append(data) 37 | return index 38 | 39 | def decode(raw_buffer): 40 | """Decode a bytes string into its corresponding data via Bencoding.""" 41 | elements = [] 42 | _decode(raw_buffer, elements) 43 | return elements[0] 44 | 45 | def encode(data): 46 | """Encode data into a bytes string via Bencoding.""" 47 | if isinstance(data, bytes): 48 | return str(len(data)).encode("ascii") + b':' + data 49 | elif isinstance(data, str): 50 | return encode(data.encode("ascii")) 51 | elif isinstance(data, int): 52 | return b'i' + str(data).encode("ascii") + b'e' 53 | elif isinstance(data, list): 54 | result = b'l' 55 | for d in data: 56 | result += encode(d) 57 | result += b'e' 58 | return result 59 | elif isinstance(data, dict): 60 | result = b'd' 61 | for key, value in data.items(): 62 | result += encode(key) 63 | result += encode(value) 64 | result += b'e' 65 | return result 66 | 67 | raise ValueError("Unexpected bencode_encode() data") 68 | -------------------------------------------------------------------------------- /seedmage.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import random 3 | import time 4 | 5 | import torrent 6 | import utils 7 | 8 | import os 9 | 10 | f_list = os.listdir('./torrent') 11 | seeder_list = list() 12 | for i in f_list: 13 | if os.path.splitext(i)[1] == '.torrent': 14 | torrent_file = torrent.File('./torrent/' + i) 15 | print("Torrent:") 16 | print(torrent_file) 17 | 18 | seeder = torrent.Seeder(torrent_file) 19 | seeder.load_peers() 20 | print("Seeder:") 21 | print(seeder) 22 | seeder_list.append(seeder) 23 | 24 | while True: 25 | time.sleep(600) 26 | for seeder in seeder_list: 27 | seeder.upload() 28 | time.sleep(30) 29 | -------------------------------------------------------------------------------- /torrent.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import hashlib 3 | import struct 4 | import random 5 | import requests 6 | 7 | import bencoding 8 | import utils 9 | 10 | class File: 11 | def __init__(self, filepath): 12 | self.filepath = filepath 13 | f = open(filepath, "rb") 14 | self.raw_torrent = f.read() 15 | f.close() 16 | self.torrent_header = bencoding.decode(self.raw_torrent) 17 | self.announce = self.torrent_header[b"announce"].decode("utf-8") 18 | torrent_info = self.torrent_header[b"info"] 19 | m = hashlib.sha1() 20 | m.update(bencoding.encode(torrent_info)) 21 | self.file_hash = m.digest() 22 | 23 | @property 24 | def total_size(self): 25 | size = 0 26 | torrent_info = self.torrent_header[b"info"] 27 | if b"files" in torrent_info: 28 | # Multiple File Mode 29 | for file_info in torrent_info[b"files"]: 30 | size += file_info[b"length"] 31 | else: 32 | # Single File Mode 33 | size = torrent_info[b"length"] 34 | 35 | return size 36 | 37 | def __str__(self): 38 | announce = self.torrent_header[b"announce"].decode("utf-8") 39 | result = "Announce: %s\n" % announce 40 | 41 | if b"creation date" in self.torrent_header: 42 | creation_date = self.torrent_header[b"creation date"] 43 | creation_date = datetime.fromtimestamp(creation_date) 44 | result += "Date: %s\n" % creation_date.strftime("%Y/%m/%d %H:%M:%S") 45 | 46 | if b"created by" in self.torrent_header: 47 | created_by = self.torrent_header[b"created by"].decode("utf-8") 48 | result += "Created by: %s\n" % created_by 49 | 50 | if b"encoding" in self.torrent_header: 51 | encoding = self.torrent_header[b"encoding"].decode("utf-8") 52 | result += "Encoding: %s\n" % encoding 53 | 54 | torrent_info = self.torrent_header[b"info"] 55 | piece_len = torrent_info[b"piece length"] 56 | result += "Piece len: %s\n" % utils.sizeof_fmt(piece_len) 57 | pieces = len(torrent_info[b"pieces"]) / 20 58 | result += "Pieces: %d\n" % pieces 59 | 60 | torrent_name = torrent_info[b"name"].decode("utf-8") 61 | result += "Name: %s\n" % torrent_name 62 | piece_len = torrent_info[b"piece length"] 63 | 64 | # if b"files" in torrent_info: 65 | # # Multiple File Mode 66 | # result += "Files:\n" 67 | # for file_info in torrent_info[b"files"]: 68 | # fullpath = "/".join([x.decode("utf-8") for x in file_info[b"path"]]) 69 | # result += " '%s' (%s)\n" % (fullpath, 70 | # utils.sizeof_fmt(file_info[b"length"])) 71 | # else: 72 | # # Single File Mode 73 | # result += "Length: %s\n" % utils.sizeof_fmt(torrent_info[b"length"]) 74 | # if b"md5sum" in torrent_info: 75 | # result += "Md5: %s\n" % torrent_info[b"md5sum"] 76 | 77 | return result 78 | 79 | 80 | class Seeder: 81 | HTTP_HEADERS = { 82 | "Accept-Encoding": "gzip", 83 | "User-Agent": "Deluge 1.3.15" 84 | } 85 | 86 | def __init__(self, torrent): 87 | self.torrent = torrent 88 | self.peer_id = "-DE13F0-" + utils.random_id(12) 89 | self.download_key = utils.random_id(12) 90 | self.port = 12394 91 | 92 | def load_peers(self): 93 | tracker_url = self.torrent.announce 94 | http_params = { 95 | "info_hash": self.torrent.file_hash, 96 | "peer_id": self.peer_id.encode("ascii"), 97 | "port": self.port, 98 | "uploaded": 0, 99 | "downloaded": 0, 100 | "left": 0, # 假下载模式:self.torrent.total_size 假上传模式:0 101 | "event": "started", 102 | "key": self.download_key, 103 | "compact": 1, 104 | "numwant": 200, 105 | "supportcrypto": 1, 106 | "no_peer_id": 1 107 | } 108 | req = requests.get(tracker_url, params=http_params, 109 | headers=self.HTTP_HEADERS) 110 | self.info = bencoding.decode(req.content) 111 | 112 | def upload(self): 113 | tracker_url = self.torrent.announce 114 | http_params = { 115 | "info_hash": self.torrent.file_hash, 116 | "peer_id": self.peer_id.encode("ascii"), 117 | "port": self.port, 118 | "uploaded": 0, # 如果要作弊上传速度 119 | "downloaded": 0, 120 | "left": 0, # 假下载模式:self.torrent.total_size 假上传模式:0 121 | "key": self.download_key, 122 | "compact": 1, 123 | "numwant": 0, 124 | "supportcrypto": 1, 125 | "no_peer_id": 1 126 | } 127 | requests.get(tracker_url, params=http_params, headers=self.HTTP_HEADERS) 128 | 129 | @property 130 | def peers(self): 131 | result = [] 132 | peers = self.info[b"peers"] 133 | for i in range(len(peers)//6): 134 | ip = peers[i:i+4] 135 | ip = '.'.join("%d" %x for x in ip) 136 | port = peers[i+4:i+6] 137 | port = struct.unpack(">H", port)[0] 138 | result.append("%s:%d\n" % (ip, port)) 139 | return result 140 | 141 | def __str__(self): 142 | result = "Peer ID: %s\n" % self.peer_id 143 | result += "Key: %s\n" % self.download_key 144 | result += "Port: %d\n" % self.port 145 | return result 146 | -------------------------------------------------------------------------------- /torrent/PLACE_TORRENT_FILE_HERE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickfox-taterli/fakeseeder/6c6a259c7db989cbfa8c44ee2135330553d83140/torrent/PLACE_TORRENT_FILE_HERE -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import string 2 | import random 3 | 4 | def sizeof_fmt(num, suffix='B'): 5 | for unit in ['','K','M','G','T','P','E','Z']: 6 | if abs(num) < 1024.0: 7 | return "%3.1f%s%s" % (num, unit, suffix) 8 | num /= 1024.0 9 | return "%.1f%s%s" % (num, 'Yi', suffix) 10 | 11 | def urlencode(bytes): 12 | result = "" 13 | valids = (string.ascii_letters + "_.").encode("ascii") 14 | for b in bytes: 15 | if b in valids: 16 | result += chr(b) 17 | elif b == " ": 18 | result += "+" 19 | else: 20 | result += "%%%02X" % b 21 | return result 22 | 23 | def random_id(length): 24 | return ''.join(random.choices(string.ascii_letters + string.digits, k=length)) --------------------------------------------------------------------------------