mirror of
https://github.com/Viren070/MediaFusion.git
synced 2025-12-01 23:21:11 +01:00
Add torrent blocking feature for DMCA (#302)
This commit is contained in:
+1
-1
@@ -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(
|
||||
|
||||
+16
-4
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<option value="add_tv_metadata">Add TV Metadata</option>
|
||||
<option value="add_m3u_playlist">Add M3U Playlist</option>
|
||||
<option value="update_imdb_data">Update IMDb Data</option>
|
||||
<option value="block_torrent">Block Torrent</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +42,8 @@
|
||||
<div id="torrentUploadParameters" style="display: none;">
|
||||
<div class="mb-3">
|
||||
<label for="torrentImdbId" class="form-label">IMDb ID</label>
|
||||
<input type="text" class="form-control" id="torrentImdbId" name="meta_id" maxlength="10" placeholder="Enter IMDb ID (e.g., tt1234567)" value="{% if prefill_data.meta_id %}{{ prefill_data.meta_id }}{% endif %}">
|
||||
<input type="text" class="form-control" id="torrentImdbId" name="meta_id" maxlength="10" placeholder="Enter IMDb ID (e.g., tt1234567)"
|
||||
value="{% if prefill_data.meta_id %}{{ prefill_data.meta_id }}{% endif %}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="metaType" class="form-label">Meta Type</label>
|
||||
@@ -235,6 +237,13 @@
|
||||
<input type="text" class="form-control" id="imdbId" name="imdb_id" placeholder="Enter IMDb ID (e.g., tt1234567)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="blockTorrentParameters" style="display: none;">
|
||||
<div class="mb-3">
|
||||
<label for="blockTorrentInfoHash" class="form-label">Torrent Info Hash</label>
|
||||
<input type="text" class="form-control" id="blockTorrentInfoHash" name="blockTorrentInfoHash" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -255,7 +264,7 @@
|
||||
</div>
|
||||
|
||||
<div class="button-container mt-5">
|
||||
<button type="button" class="btn btn-primary" id="submitBtn" onclick="submitScraperForm()">Run Scraper</button>
|
||||
<button type="button" class="btn btn-primary" id="submitBtn" onclick="submitScraperForm()">Run</button>
|
||||
<div id="loadingSpinner" class="spinner-border text-primary" role="status" style="display: none;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
|
||||
@@ -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;
|
||||
|
||||
+20
-2
@@ -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."}
|
||||
|
||||
Reference in New Issue
Block a user