implemented BEP 36 (Torrent RSS feeds) in magneticow
http://www.bittorrent.org/beps/bep_0036.html
This commit is contained in:
parent
d877ba2475
commit
65dc6737e1
@ -16,6 +16,7 @@ import collections
|
||||
import functools
|
||||
import datetime as dt
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import logging
|
||||
import sqlite3
|
||||
import os
|
||||
@ -41,7 +42,7 @@ magneticod_db = None
|
||||
# Adapted from: http://flask.pocoo.org/snippets/8/
|
||||
# (c) Copyright 2010 - 2017 by Armin Ronacher
|
||||
# BEGINNING OF THE COPYRIGHTED CONTENT
|
||||
def check_auth(supplied_username, supplied_password):
|
||||
def is_authorized(supplied_username, supplied_password):
|
||||
""" This function is called to check if a username / password combination is valid. """
|
||||
# Because we do monkey-patch! [in magneticow.__main__.py:main()]
|
||||
for username, password in app.arguments.user: # pylint: disable=maybe-no-member
|
||||
@ -64,13 +65,24 @@ def requires_auth(f):
|
||||
@functools.wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
auth = flask.request.authorization
|
||||
if not auth or not check_auth(auth.username, auth.password):
|
||||
if not auth or not is_authorized(auth.username, auth.password):
|
||||
return authenticate()
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
# END OF THE COPYRIGHTED CONTENT
|
||||
|
||||
|
||||
def generate_feed_hash(username: str, password: str, filter_: str) -> str:
|
||||
"""
|
||||
Deterministically generates the feed hash from given username, password, and filter.
|
||||
Hash is the hex encoding of the SHA256 sum.
|
||||
:param username:
|
||||
:param password:
|
||||
:param filter_:
|
||||
:return:
|
||||
"""
|
||||
return hashlib.sha256((username + "\0" + password + "\0" + filter_).encode()).digest().hex()
|
||||
|
||||
@app.route("/")
|
||||
@requires_auth
|
||||
def home_page():
|
||||
@ -128,6 +140,9 @@ def search_torrents():
|
||||
else:
|
||||
context["next_page_exists"] = True
|
||||
|
||||
username, password = flask.request.authorization.username, flask.request.authorization.password
|
||||
context["subscription_url"] = "/feed?filter=%s&hash=%s" % (search, generate_feed_hash(username, password, search))
|
||||
|
||||
return flask.render_template("torrents.html", **context)
|
||||
|
||||
|
||||
@ -158,6 +173,9 @@ def newest_torrents():
|
||||
else:
|
||||
context["next_page_exists"] = True
|
||||
|
||||
username, password = flask.request.authorization.username, flask.request.authorization.password
|
||||
context["subscription_url"] = "/feed?filter=&hash=%s" % (generate_feed_hash(username, password, ""),)
|
||||
|
||||
return flask.render_template("torrents.html", **context)
|
||||
|
||||
|
||||
@ -241,6 +259,56 @@ def statistics():
|
||||
})
|
||||
|
||||
|
||||
@app.route("/feed")
|
||||
def feed():
|
||||
filter_ = flask.request.args["filter"]
|
||||
hash_ = flask.request.args["hash"]
|
||||
# Check for all possible users who might be requesting.
|
||||
# pylint disabled: because we do monkey-patch! [in magneticow.__main__.py:main()]
|
||||
for username, password in app.arguments.user: # pylint: disable=maybe-no-member
|
||||
if generate_feed_hash(username, password, filter_) == hash_:
|
||||
break
|
||||
else:
|
||||
return flask.Response(
|
||||
"Could not verify your access level for that URL (wrong hash).\n",
|
||||
401
|
||||
)
|
||||
|
||||
context = {}
|
||||
|
||||
if filter_:
|
||||
context["title"] = "`%s` - magneticow" % (filter_,)
|
||||
with magneticod_db:
|
||||
cur = magneticod_db.execute(
|
||||
"SELECT "
|
||||
" name, "
|
||||
" info_hash "
|
||||
"FROM torrents "
|
||||
"INNER JOIN ("
|
||||
" SELECT docid AS id, rank(matchinfo(fts_torrents, 'pcnxal')) AS rank "
|
||||
" FROM fts_torrents "
|
||||
" WHERE name MATCH ? "
|
||||
" ORDER BY rank ASC"
|
||||
" LIMIT 50"
|
||||
") AS ranktable USING(id);",
|
||||
(filter_, )
|
||||
)
|
||||
context["items"] = [{"title": r[0], "info_hash": r[1].hex()} for r in cur]
|
||||
else:
|
||||
context["title"] = "The Newest Torrents - magneticow"
|
||||
with magneticod_db:
|
||||
cur = magneticod_db.execute(
|
||||
"SELECT "
|
||||
" name, "
|
||||
" info_hash "
|
||||
"FROM torrents "
|
||||
"ORDER BY id DESC LIMIT 50"
|
||||
)
|
||||
context["items"] = [{"title": r[0], "info_hash": r[1].hex()} for r in cur]
|
||||
|
||||
return flask.render_template("feed.xml", **context), 200, {"Content-Type": "application/rss+xml; charset=utf-8"}
|
||||
|
||||
|
||||
def initialize_magneticod_db() -> None:
|
||||
global magneticod_db
|
||||
|
||||
|
@ -22,6 +22,7 @@ header form {
|
||||
width: 100%;
|
||||
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
|
13
magneticow/magneticow/templates/feed.xml
Normal file
13
magneticow/magneticow/templates/feed.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>{{ title }}</title>
|
||||
{% for item in items %}
|
||||
<item>
|
||||
<title>{{ item.title }}</title>
|
||||
<guid>{{ item.info_hash }}</guid>
|
||||
<enclosure url="magnet:?xt=urn:btih:{{ item.info_hash }}&dn={{ item.title }}" type="application/x-bittorrent" />
|
||||
</item>
|
||||
{% endfor %}
|
||||
</channel>
|
||||
</rss>
|
@ -14,6 +14,10 @@
|
||||
<form action="/torrents" method="get" autocomplete="off" role="search">
|
||||
<input type="search" name="search" placeholder="Search the BitTorrent DHT" value="{{ search }}">
|
||||
</form>
|
||||
<div>
|
||||
<a href="{{ subscription_url }}"><img src="{{ url_for('static', filename='assets/feed.png') }}"
|
||||
alt="feed icon" title="subscribe" /> subscribe</a>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<table>
|
||||
|
Loading…
Reference in New Issue
Block a user