diff --git a/api/middleware.py b/api/middleware.py
index 4de2323..f5d5da8 100644
--- a/api/middleware.py
+++ b/api/middleware.py
@@ -59,7 +59,7 @@ class UserDataMiddleware(BaseHTTPMiddleware):
user_data = crypto.decrypt_user_data(secret_str)
# validate api password if set
- if settings.api_password and settings.is_public_instance is False:
+ if settings.is_public_instance is False:
is_auth_required = getattr(endpoint, "auth_required", False)
if is_auth_required and user_data.api_password != settings.api_password:
return Response(
diff --git a/db/crud.py b/db/crud.py
index 32d0d40..2408e31 100644
--- a/db/crud.py
+++ b/db/crud.py
@@ -64,6 +64,7 @@ async def get_meta_list(
else:
query_filters = {"catalog": {"$in": [catalog]}}
+ query_filters["is_blocked"] = {"$ne": True}
match_filter = {
"type": catalog_type,
}
@@ -265,7 +266,9 @@ async def get_cached_torrent_streams(
# If the data is not in the cache, query it from the database
if season is not None and episode is not None:
streams = (
- await TorrentStreams.find({"meta_id": video_id})
+ await TorrentStreams.find(
+ {"meta_id": video_id, "is_blocked": {"$ne": True}}
+ )
.find(
{
"season.season_number": season,
@@ -277,7 +280,9 @@ async def get_cached_torrent_streams(
)
else:
streams = (
- await TorrentStreams.find({"meta_id": video_id})
+ await TorrentStreams.find(
+ {"meta_id": video_id, "is_blocked": {"$ne": True}}
+ )
.sort("-updated_at")
.to_list()
)
@@ -802,7 +807,12 @@ async def process_search_query(
"localField": "_id",
"foreignField": "meta_id",
"pipeline": [
- {"$match": {"catalog": {"$in": user_data.selected_catalogs}}},
+ {
+ "$match": {
+ "catalog": {"$in": user_data.selected_catalogs},
+ "is_blocked": {"$ne": True},
+ }
+ },
{"$count": "num_torrents"},
],
"as": "torrent_count",
@@ -885,7 +895,9 @@ async def process_tv_search_query(search_query: str, namespace: str) -> dict:
async def get_stream_by_info_hash(info_hash: str) -> TorrentStreams | None:
- stream = await TorrentStreams.get(info_hash)
+ stream = await TorrentStreams.find_one(
+ {"_id": info_hash, "is_blocked": {"$ne": True}}
+ )
return stream
diff --git a/db/models.py b/db/models.py
index 06c2e8b..41bb9fb 100644
--- a/db/models.py
+++ b/db/models.py
@@ -45,6 +45,7 @@ class TorrentStreams(Document):
seeders: Optional[int] = None
cached: Optional[bool] = Field(default=False, exclude=True)
indexer_flags: Optional[list[str]] = Field(default_factory=list)
+ is_blocked: Optional[bool] = False
def __eq__(self, other):
if not isinstance(other, TorrentStreams):
diff --git a/db/schemas.py b/db/schemas.py
index ecbd3a2..8eb4740 100644
--- a/db/schemas.py
+++ b/db/schemas.py
@@ -350,3 +350,8 @@ class TVMetaDataUpload(BaseModel):
class KodiConfig(BaseModel):
code: str = Field(max_length=6)
manifest_url: HttpUrl
+
+
+class BlockTorrent(BaseModel):
+ info_hash: str
+ api_password: str
diff --git a/resources/html/scraper.html b/resources/html/scraper.html
index 42b772c..ecaffd4 100644
--- a/resources/html/scraper.html
+++ b/resources/html/scraper.html
@@ -32,6 +32,7 @@
+
@@ -41,7 +42,8 @@
+
+
+
+
+
+
+
@@ -255,7 +264,7 @@
-
+
Loading...
diff --git a/resources/js/scraperControl.js b/resources/js/scraperControl.js
index 0994221..a54852a 100644
--- a/resources/js/scraperControl.js
+++ b/resources/js/scraperControl.js
@@ -201,6 +201,7 @@ function updateFormFields() {
setElementDisplay("imdbDataParameters", "none");
setElementDisplay("torrentUploadParameters", "none");
setElementDisplay("apiPasswordContainer", "none");
+ setElementDisplay('blockTorrentParameters', 'none');
// Get the selected scraper type
const scraperType = document.getElementById('scraperSelect').value;
@@ -233,6 +234,9 @@ function updateFormFields() {
case 'update_imdb_data':
setElementDisplay("imdbDataParameters", "block");
break;
+ case 'block_torrent':
+ setElementDisplay("blockTorrentParameters", "block");
+ break;
default:
// Optionally handle any default cases if needed
break;
@@ -524,6 +528,40 @@ async function handleScrapyParameters(payload, submitBtn, loadingSpinner) {
}
}
+async function handleBlockTorrent(apiPassword, submitBtn, loadingSpinner) {
+ const infoHash = document.getElementById('blockTorrentInfoHash').value.trim();
+ if (!infoHash) {
+ showNotification('Torrent Info Hash is required.', 'error');
+ resetButton(submitBtn, loadingSpinner);
+ return;
+ }
+
+ try {
+ const response = await fetch('/scraper/block_torrent', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ info_hash: infoHash,
+ api_password: apiPassword
+ })
+ });
+
+ const data = await response.json();
+ if (data.detail) {
+ showNotification(data.detail, 'error');
+ } else {
+ showNotification(data.status, 'success');
+ }
+ } catch (error) {
+ console.error('Error blocking torrent:', error);
+ showNotification(`Error blocking torrent. Error: ${error.toString()}`, 'error');
+ } finally {
+ resetButton(submitBtn, loadingSpinner);
+ }
+}
+
// Main function
async function submitScraperForm() {
const apiPassword = document.getElementById('api_password').value;
@@ -550,6 +588,9 @@ async function submitScraperForm() {
case 'update_imdb_data':
await handleUpdateImdbData(submitBtn, loadingSpinner);
break;
+ case 'block_torrent':
+ await handleBlockTorrent(apiPassword, submitBtn, loadingSpinner);
+ break;
default:
await handleScrapyParameters(payload, submitBtn, loadingSpinner);
break;
diff --git a/scrapers/routes.py b/scrapers/routes.py
index f922e6f..11b341f 100644
--- a/scrapers/routes.py
+++ b/scrapers/routes.py
@@ -30,8 +30,8 @@ router = APIRouter()
def validate_api_password(api_password: str):
- if settings.api_password and api_password != settings.api_password:
- raise HTTPException(status_code=200, detail="Invalid API password.")
+ if api_password != settings.api_password:
+ raise HTTPException(status_code=401, detail="Invalid API password.")
return True
@@ -377,3 +377,21 @@ async def handle_series_stream_store(info_hash, parsed_data, video_id, season):
await store_new_torrent_streams([torrent_stream])
return torrent_stream
+
+
+@router.post("/block_torrent", tags=["scraper"])
+async def block_torrent(block_data: schemas.BlockTorrent):
+ validate_api_password(block_data.api_password)
+ torrent_stream = await TorrentStreams.get(block_data.info_hash)
+ if not torrent_stream:
+ raise HTTPException(status_code=404, detail="Torrent not found.")
+ if torrent_stream.is_blocked:
+ return {"status": f"Torrent {block_data.info_hash} is already blocked."}
+ torrent_stream.is_blocked = True
+ try:
+ await torrent_stream.save()
+ except Exception as e:
+ raise HTTPException(
+ status_code=500, detail=f"Failed to block torrent: {str(e)}"
+ )
+ return {"status": f"Torrent {block_data.info_hash} has been successfully blocked."}