|
|
from flask import Flask, request, jsonify |
|
|
from bs4 import BeautifulSoup |
|
|
import requests |
|
|
import re |
|
|
import webbrowser |
|
|
|
|
|
|
|
|
app = Flask(__name__) |
|
|
|
|
|
html_content = """ |
|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Torrent</title> |
|
|
<style> |
|
|
body { |
|
|
font-family: Arial, sans-serif; |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
background-color: #171a21; |
|
|
color: #fff; |
|
|
} |
|
|
#container { |
|
|
max-width: 800px; |
|
|
margin: 20px auto; |
|
|
padding: 20px; |
|
|
background-color: #2c2f35; |
|
|
border-radius: 8px; |
|
|
} |
|
|
h1 { |
|
|
text-align: center; |
|
|
color: #66c0f4; |
|
|
} |
|
|
#search-container { |
|
|
margin-bottom: 20px; |
|
|
text-align: center; |
|
|
} |
|
|
#search-input, #category-select { |
|
|
padding: 10px; |
|
|
border: none; |
|
|
border-radius: 4px; |
|
|
margin: 5px; |
|
|
} |
|
|
#search-input { |
|
|
width: 50%; |
|
|
} |
|
|
#category-select { |
|
|
width: 20%; |
|
|
} |
|
|
#search-button { |
|
|
padding: 10px 20px; |
|
|
background-color: #4b5263; |
|
|
color: #fff; |
|
|
border: none; |
|
|
border-radius: 4px; |
|
|
cursor: pointer; |
|
|
} |
|
|
#game-list { |
|
|
list-style-type: none; |
|
|
padding: 0; |
|
|
} |
|
|
.game-item { |
|
|
margin-bottom: 10px; |
|
|
padding: 10px; |
|
|
background-color: #3e4251; |
|
|
border-radius: 4px; |
|
|
} |
|
|
.game-name { |
|
|
font-size: 18px; |
|
|
color: #66c0f4; |
|
|
} |
|
|
.game-details { |
|
|
font-size: 14px; |
|
|
} |
|
|
.download-button { |
|
|
padding: 8px 16px; |
|
|
background-color: #66c0f4; |
|
|
color: #fff; |
|
|
border: none; |
|
|
border-radius: 4px; |
|
|
cursor: pointer; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div id="container"> |
|
|
<h1>Torrent</h1> |
|
|
<div id="search-container"> |
|
|
<input type="text" id="search-input" placeholder="Enter keyword"> |
|
|
<select id="category-select"> |
|
|
<option value="0">Все</option> |
|
|
<option value="movies">Фильмы</option> |
|
|
<option value="series">Сериалы</option> |
|
|
<option value="6">Телевизор</option> |
|
|
<option value="7">Мультипликация</option> |
|
|
<option value="10">Аниме</option> |
|
|
<option value="2">Музыка</option> |
|
|
<option value="8">Игры</option> |
|
|
<option value="9">Софт</option> |
|
|
<option value="13">Спорт и здоровье</option> |
|
|
<option value="15">Юмор</option> |
|
|
<option value="14">Хозяйство и быт</option> |
|
|
<option value="11">Книги</option> |
|
|
<option value="3">Другое</option> |
|
|
</select> |
|
|
<button id="search-button">Search</button> |
|
|
</div> |
|
|
<ul id="game-list"></ul> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.getElementById("search-button").addEventListener("click", function() { |
|
|
searchGames(); |
|
|
}); |
|
|
|
|
|
document.getElementById("search-input").addEventListener("keypress", function(event) { |
|
|
if (event.key === "Enter") { |
|
|
searchGames(); |
|
|
} |
|
|
}); |
|
|
|
|
|
function searchGames() { |
|
|
var query = document.getElementById("search-input").value.trim(); |
|
|
var category = document.getElementById("category-select").value; |
|
|
if (query !== "") { |
|
|
var url = "/search/" + category + "/" + query; |
|
|
fetch(url) |
|
|
.then(response => response.json()) |
|
|
.then(data => { |
|
|
var gameList = document.getElementById("game-list"); |
|
|
gameList.innerHTML = ""; |
|
|
data.forEach(game => { |
|
|
var listItem = document.createElement("li"); |
|
|
listItem.className = "game-item"; |
|
|
var nameElem = document.createElement("div"); |
|
|
nameElem.className = "game-name"; |
|
|
nameElem.textContent = game.name; |
|
|
listItem.appendChild(nameElem); |
|
|
if (game.size) { |
|
|
var detailsElem = document.createElement("div"); |
|
|
detailsElem.className = "game-details"; |
|
|
detailsElem.textContent = "Size: " + game.size + ", Seeders: " + game.seeders + ", Leechers: " + game.leechers; |
|
|
listItem.appendChild(detailsElem); |
|
|
} |
|
|
var downloadButton = document.createElement("button"); |
|
|
downloadButton.className = "download-button"; |
|
|
downloadButton.textContent = "Download"; |
|
|
downloadButton.addEventListener("click", function() { |
|
|
window.open(game.download_link); |
|
|
}); |
|
|
listItem.appendChild(downloadButton); |
|
|
gameList.appendChild(listItem); |
|
|
}); |
|
|
}) |
|
|
.catch(error => console.log(error)); |
|
|
} |
|
|
} |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
""" |
|
|
|
|
|
def get_game_name(html): |
|
|
soup = BeautifulSoup(html, 'html.parser') |
|
|
anchor = soup.find('a', {'href': re.compile(r'\/torrent\/\d+\/')}) |
|
|
if anchor: |
|
|
return anchor.text.strip() |
|
|
return None |
|
|
|
|
|
def get_game_size(html): |
|
|
soup = BeautifulSoup(html, 'html.parser') |
|
|
size_td = soup.find("td", align="right", text=re.compile(r'\d+\.\d+\s*(GB|MB)')) |
|
|
if size_td: |
|
|
return size_td.text.strip() |
|
|
return None |
|
|
|
|
|
def search_games(category, query): |
|
|
if not query: |
|
|
return [] |
|
|
|
|
|
if category == "all": |
|
|
url = f"https://rutor.info/search/0/0/000/0/{query}/" |
|
|
elif category == "movies": |
|
|
urls = [ |
|
|
f"https://rutor.info/search/0/1/000/0/{query}/", |
|
|
f"https://rutor.info/search/0/5/000/0/{query}/", |
|
|
f"https://rutor.info/search/0/12/000/0/{query}/" |
|
|
] |
|
|
games = [] |
|
|
for url in urls: |
|
|
response = requests.get(url) |
|
|
if response.status_code == 200: |
|
|
soup = BeautifulSoup(response.text, "html.parser") |
|
|
torrents = soup.find_all("tr", class_="tum") |
|
|
for torrent in torrents: |
|
|
name = get_game_name(str(torrent)) |
|
|
if name: |
|
|
size = get_game_size(str(torrent)) |
|
|
seeders = torrent.find("span", class_="green").text.strip() |
|
|
leechers = torrent.find("span", class_="red").text.strip() |
|
|
download_link = torrent.find("a", class_="downgif")["href"] |
|
|
game_info = {'name': name, 'size': size, 'seeders': seeders, 'leechers': leechers, 'download_link': download_link} |
|
|
games.append(game_info) |
|
|
return games |
|
|
elif category == "series": |
|
|
urls = [ |
|
|
f"https://rutor.info/search/0/4/000/0/{query}/", |
|
|
f"https://rutor.info/search/0/16/000/0/{query}/" |
|
|
] |
|
|
games = [] |
|
|
for url in urls: |
|
|
response = requests.get(url) |
|
|
if response.status_code == 200: |
|
|
soup = BeautifulSoup(response.text, "html.parser") |
|
|
torrents = soup.find_all("tr", class_="tum") |
|
|
for torrent in torrents: |
|
|
name = get_game_name(str(torrent)) |
|
|
if name: |
|
|
size = get_game_size(str(torrent)) |
|
|
seeders = torrent.find("span", class_="green").text.strip() |
|
|
leechers = torrent.find("span", class_="red").text.strip() |
|
|
download_link = torrent.find("a", class_="downgif")["href"] |
|
|
game_info = {'name': name, 'size': size, 'seeders': seeders, 'leechers': leechers, 'download_link': download_link} |
|
|
games.append(game_info) |
|
|
return games |
|
|
else: |
|
|
url = f"https://rutor.info/search/0/{category}/000/0/{query}/" |
|
|
response = requests.get(url) |
|
|
if response.status_code == 200: |
|
|
soup = BeautifulSoup(response.text, "html.parser") |
|
|
torrents = soup.find_all("tr", class_="tum") |
|
|
games = [] |
|
|
for torrent in torrents: |
|
|
name = get_game_name(str(torrent)) |
|
|
if name: |
|
|
size = get_game_size(str(torrent)) |
|
|
seeders = torrent.find("span", class_="green").text.strip() |
|
|
leechers = torrent.find("span", class_="red").text.strip() |
|
|
download_link = torrent.find("a", class_="downgif")["href"] |
|
|
game_info = {'name': name, 'size': size, 'seeders': seeders, 'leechers': leechers, 'download_link': download_link} |
|
|
games.append(game_info) |
|
|
return games |
|
|
return [] |
|
|
|
|
|
@app.route('/') |
|
|
def index(): |
|
|
return html_content |
|
|
|
|
|
@app.route('/search/<category>/<query>') |
|
|
def search_endpoint(category, query): |
|
|
games = search_games(category, query) |
|
|
return jsonify(games) |
|
|
|
|
|
if __name__ == '__main__': |
|
|
app.run(debug=True) |
|
|
|