// ==UserScript==
// @name Bypass FileCrypt (New)
// @namespace Bhunter
// @version 1.0.3
// @description Bypass FileCrypt
// @author Bhunter
// @license MIT
// @match http://filecrypt.cc/*
// @match http://www.filecrypt.cc/*
// @match http://filecrypt.co/*
// @match http://www.filecrypt.co/*
// @match https://filecrypt.cc/*
// @match https://www.filecrypt.cc/*
// @match https://filecrypt.co/*
// @match https://www.filecrypt.co/*
// @run-at document-end
// @connect dcrypt.it
// @connect self
// @grant GM.xmlHttpRequest
// ==/UserScript==
(function() {
'use strict';
// Determine if dark theme is used
const isDarkTheme = document.head.querySelector('meta[name="theme-color"]') !== null ||
document.body.classList.contains('dark') ||
window.getComputedStyle(document.body).backgroundColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)/)?.[1] < 100;
// Add stylesheet to document
addStylesheet(isDarkTheme);
// Remove ads
removeAds();
// Apply main functionality based on URL
if (document.location.href.includes("/Link/")) {
processSingleLink();
} else if (document.location.href.includes("/Container/")) {
waitForCaptchaSolved();
}
})();
// Add stylesheet to document
function addStylesheet(isDarkTheme) {
const style = document.createElement('style');
// Define the colors based on theme
const colors = isDarkTheme ? {
background: '#1e1e2e',
text: '#cdd6f4',
accent: '#cba6f7',
border: '#313244',
itemBg: '#181825',
itemHover: '#11111b',
actionBg: '#45475a',
actionText: '#cdd6f4'
} : {
background: '#ffffff',
text: '#333333',
accent: '#4f46e5',
border: '#e5e7eb',
itemBg: '#f9fafb',
itemHover: '#f3f4f6',
actionBg: '#e0e7ff',
actionText: '#4f46e5'
};
// Stylesheet content
style.textContent = `
/* Main container */
.fc-container {
background-color: ${colors.background};
color: ${colors.text};
border: 1px solid ${colors.border};
border-radius: 12px;
box-shadow: 0 10px 15px -3px ${isDarkTheme ? 'rgba(0, 0, 0, 0.4)' : 'rgba(0, 0, 0, 0.1)'};
max-width: 560px;
margin: 40px auto 30px;
overflow: hidden;
font-size: 14px;
line-height: 1.5;
position: relative;
z-index: 10;
}
/* Header */
.fc-header {
padding: 14px 18px;
border-bottom: 1px solid ${colors.border};
display: flex;
justify-content: space-between;
align-items: center;
}
.fc-title {
margin: 0;
font-weight: 600;
font-size: 16px;
}
.fc-counter {
padding: 4px 10px;
border-radius: 20px;
font-size: 12px;
background-color: ${colors.actionBg};
color: ${colors.actionText};
}
/* Content area */
.fc-content {
max-height: 250px;
overflow-y: auto;
padding: 4px 0;
scrollbar-width: thin;
scrollbar-color: ${colors.border} transparent;
}
.fc-content::-webkit-scrollbar {
width: 6px;
}
.fc-content::-webkit-scrollbar-track {
background: transparent;
}
.fc-content::-webkit-scrollbar-thumb {
background-color: ${colors.border};
border-radius: 3px;
}
/* Loading */
.fc-loading {
padding: 16px;
text-align: center;
}
.fc-loading p {
margin-top: 12px;
font-size: 14px;
}
.fc-spinner {
animation: fc-rotate 2s linear infinite;
}
.fc-spinner-path {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
animation: fc-dash 1.5s ease-in-out infinite;
stroke: ${colors.accent};
}
@keyframes fc-rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes fc-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
/* Domain headers */
.fc-domain-header {
padding: 6px 16px;
font-size: 13px;
font-weight: 500;
color: ${colors.accent};
display: flex;
align-items: center;
gap: 6px;
}
.fc-domain-header:not(:first-child) {
margin-top: 10px;
}
.fc-domain-count {
background-color: ${colors.actionBg};
border-radius: 10px;
padding: 1px 6px;
font-size: 11px;
}
/* Link items */
.fc-link-item {
padding: 8px 16px;
margin: 4px 0;
display: flex;
align-items: center;
gap: 10px;
border-radius: 4px;
transition: background-color 0.2s;
cursor: pointer;
}
.fc-link-item:hover {
background-color: ${colors.itemHover};
}
.fc-link-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
font-size: 14px;
color: white !important;
opacity: 0.9;
}
/* Copy button */
.fc-copy-btn {
width: 28px;
height: 28px;
min-width: 28px;
background-color: transparent;
color: ${colors.accent};
border: none;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 0;
transition: background-color 0.2s;
margin: 0;
}
.fc-copy-btn:hover {
background-color: ${colors.actionBg};
}
/* Footer */
.fc-footer {
padding: 12px 16px;
border-top: 1px solid ${colors.border};
display: flex;
justify-content: space-between;
align-items: center;
}
.fc-info-text {
opacity: 0.7;
font-size: 12px;
}
.fc-copy-all {
padding: 8px 12px;
background-color: ${colors.accent};
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s ease;
}
.fc-copy-all:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.fc-copy-all:hover:not(:disabled) {
filter: brightness(1.1);
}
`;
document.head.appendChild(style);
}
// Remove ads
function removeAds() {
const usenetAds = document.querySelectorAll('a[href*="/pink/"]');
for (const ad of usenetAds) {
if (ad.parentNode) {
ad.parentNode.remove();
}
}
}
// Check if captcha is solved by looking for download buttons
function waitForCaptchaSolved() {
// Function to check if captcha is solved based on visible elements
function isCaptchaSolved() {
// Look for download buttons or elements that appear after captcha
return document.querySelectorAll('.dlcdownload').length > 0;
}
// If captcha is already solved, proceed immediately
if (isCaptchaSolved()) {
processContainerPage();
return;
}
// Otherwise, wait for captcha to be solved
const captchaObserver = new MutationObserver((mutations, observer) => {
if (isCaptchaSolved()) {
observer.disconnect();
processContainerPage();
}
});
captchaObserver.observe(document.body, {
childList: true,
subtree: true
});
}
// Process single link page
async function processSingleLink() {
if (document.body.getElementsByTagName("SCRIPT").length === 0) {
window.stop();
let htmlContent = document.body.innerHTML;
if (!htmlContent || document.body.children.length === 0) {
try {
const response = await fetch(document.location.href);
htmlContent = await response.text();
} catch (error) {
console.error("Failed to fetch page content:", error);
return;
}
}
const httpIndex = htmlContent.lastIndexOf("http");
if (httpIndex !== -1) {
const endIndex = htmlContent.indexOf('id=', httpIndex) + 43;
let finalUrl = htmlContent.substring(httpIndex, endIndex).replace(/&/g, '&');
window.location.href = finalUrl;
}
}
}
// Process container page
function processContainerPage() {
// Find the best container to insert our link box
const containerSection = findBestContainer();
// Create container elements
const { container, content, counter, copyAllBtn } = createLinkBox();
// Insert the box at the appropriate location
containerSection.insertBefore(container, containerSection.firstChild);
// Try to get DLC file
const dlcButtons = document.getElementsByClassName("dlcdownload");
if (dlcButtons.length > 0) {
const dlcId = dlcButtons[0].getAttribute("onclick")?.split("'")[1];
if (dlcId) {
fetchDlcAndDecrypt(dlcId, { content, counter, copyAllBtn });
return;
}
}
// Fall back to manual link extraction
extractLinks({ content, counter, copyAllBtn });
}
// Find the best container for inserting our box
function findBestContainer() {
// Try various selectors in order of preference
const selectors = [
'.content .window',
'.download',
'.content',
'main',
'article',
'.container',
'#container'
];
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) {
return element;
}
}
// Fallback to body if no suitable container found
return document.body;
}
// Create DOM structure for the link box
function createLinkBox() {
// Create container
const container = document.createElement("div");
container.className = "fc-container";
// Create header
const header = document.createElement("div");
header.className = "fc-header";
const title = document.createElement("h3");
title.className = "fc-title";
title.innerHTML = "🔓 Decrypted Links";
const counter = document.createElement("span");
counter.className = "fc-counter";
counter.id = "fc-counter";
counter.textContent = "Loading...";
header.appendChild(title);
header.appendChild(counter);
container.appendChild(header);
// Create content area
const content = document.createElement("div");
content.className = "fc-content";
content.id = "fc-content";
// Add loading animation
const loadingDiv = document.createElement("div");
loadingDiv.className = "fc-loading";
loadingDiv.id = "fc-loading";
loadingDiv.innerHTML = `
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<circle class="fc-spinner fc-spinner-path" cx="12" cy="12" r="10" fill="none" stroke-width="2" />
</svg>
<p>Decrypting links...</p>
`;
content.appendChild(loadingDiv);
container.appendChild(content);
// Create footer
const footer = document.createElement("div");
footer.className = "fc-footer";
// Add info text
const infoText = document.createElement("small");
infoText.className = "fc-info-text";
infoText.textContent = "Click link to open, or use copy button";
// Add copy all button
const copyAllBtn = document.createElement("button");
copyAllBtn.className = " fc-copy-all";
copyAllBtn.id = "fc-copy-all";
copyAllBtn.textContent = "Copy All";
copyAllBtn.disabled = true;
footer.appendChild(infoText);
footer.appendChild(copyAllBtn);
container.appendChild(footer);
return { container, content, counter, copyAllBtn };
}
// Fetch DLC file and decrypt it
async function fetchDlcAndDecrypt(dlcId, elements) {
try {
// Update the loading message
const loadingDiv = document.getElementById("fc-loading");
const loadingText = loadingDiv.querySelector("p");
loadingText.textContent = "Fetching DLC file...";
// Fetch the DLC file
const response = await fetch(`https://${document.location.hostname}/DLC/${dlcId}.dlc`);
if (!response.ok) throw new Error('Failed to fetch DLC file');
const dlcContent = await response.text();
loadingText.textContent = "Decrypting links via dcrypt.it...";
// Use GM.xmlHttpRequest for dcrypt.it (since it may require CORS handling)
GM.xmlHttpRequest({
method: "POST",
url: "http://dcrypt.it/decrypt/paste",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: "content=" + encodeURIComponent(dlcContent),
onload: function(response) {
try {
const result = JSON.parse(response.response);
if (result.success && result.success.links && result.success.links.length > 0) {
displayLinks(result.success.links, elements);
} else {
throw new Error("No links were found in the dcrypt.it response");
}
} catch (error) {
console.error("Error parsing dcrypt.it response:", error);
extractLinks(elements);
}
},
onerror: function() {
console.error("Error connecting to dcrypt.it");
extractLinks(elements);
}
});
} catch (error) {
console.error("Error fetching DLC:", error);
extractLinks(elements);
}
}
// Extract links directly from page
function extractLinks(elements) {
const loadingDiv = document.getElementById("fc-loading");
const loadingText = loadingDiv.querySelector("p");
loadingText.textContent = "Extracting links directly...";
const encLinks = document.querySelectorAll("[onclick^=openLink]");
if (encLinks.length === 0) {
showError("No links found on this page.");
return;
}
// Update counter to show progress
elements.counter.textContent = `0/${encLinks.length}`;
let completedLinks = 0;
const validLinks = [];
// Process each link with a small delay between requests to avoid overloading
const processLink = (index) => {
if (index >= encLinks.length) {
if (validLinks.length > 0) {
displayLinks(validLinks, elements);
} else {
showError("Failed to extract any valid links.");
}
return;
}
const link = encLinks[index];
const onclick = link.getAttribute("onclick");
const encParam = onclick.split("'")[1];
const encValue = link.getAttribute(encParam);
const linkUrl = `http://${document.location.hostname}/Link/${encValue}.html`;
fetchFinalLink(linkUrl)
.then(finalLink => {
completedLinks++;
elements.counter.textContent = `${completedLinks}/${encLinks.length}`;
if (finalLink) {
validLinks.push(finalLink);
}
// Process next link with a small delay
setTimeout(() => processLink(index + 1), 100);
})
.catch(() => {
completedLinks++;
elements.counter.textContent = `${completedLinks}/${encLinks.length}`;
setTimeout(() => processLink(index + 1), 100);
});
};
// Start processing links
processLink(0);
}
// Show error message
function showError(message) {
const loadingDiv = document.getElementById("fc-loading");
loadingDiv.innerHTML = `
<div style="color:var(--fc-accent,#4f46e5);font-size:24px;margin-bottom:10px">❌</div>
<p style="margin:0">${message}</p>
`;
const counter = document.getElementById("fc-counter");
if (counter) counter.textContent = "Error";
}
// Fetch a single link's destination
async function fetchFinalLink(url) {
try {
const response = await fetch(url);
if (!response.ok) return null;
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
// Try to find the redirect URL in scripts
const scripts = doc.querySelectorAll("script");
for (const script of scripts) {
if (script.textContent.includes("top.location.href=")) {
const matches = script.textContent.match(/top\.location\.href\s*=\s*['"]([^'"]+)['"]/);
if (matches && matches[1]) {
return await resolveRedirect(matches[1]);
}
}
}
return null;
} catch (error) {
console.error("Error fetching link:", error);
return null;
}
}
// Resolve final URL from redirect
async function resolveRedirect(url) {
try {
// Using fetch with HEAD method to get the final URL
const controller = new AbortController();
const signal = controller.signal;
// Set a timeout to abort the request
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, {
method: 'HEAD',
signal,
redirect: 'follow'
});
clearTimeout(timeoutId);
return response.url;
} catch (error) {
// If HEAD fails, try GET with GM.xmlHttpRequest
return new Promise((resolve) => {
GM.xmlHttpRequest({
method: "GET",
url: url,
onreadystatechange: function(response) {
if (response.readyState === 2) { // HEADERS_RECEIVED
resolve(response.finalUrl);
this.abort();
}
},
onerror: function() {
resolve(url); // Return original URL if everything fails
}
});
});
}
}
// Display links with modern UI
function displayLinks(links, elements) {
// Update counter
elements.counter.textContent = `${links.length} Links`;
// Clear loading indicator
elements.content.innerHTML = '';
// Enable copy all button
elements.copyAllBtn.disabled = false;
elements.copyAllBtn.addEventListener('click', () => {
navigator.clipboard.writeText(links.join('\n'))
.then(() => {
const originalText = elements.copyAllBtn.textContent;
elements.copyAllBtn.textContent = "✓ Copied";
setTimeout(() => {
elements.copyAllBtn.textContent = originalText;
}, 2000);
});
});
// Group links by domain for better organization
const linksByDomain = {};
links.forEach(link => {
try {
const url = new URL(link);
const domain = url.hostname;
if (!linksByDomain[domain]) {
linksByDomain[domain] = [];
}
linksByDomain[domain].push(link);
} catch (e) {
// If parsing fails, put in "Other" category
if (!linksByDomain["Other"]) {
linksByDomain["Other"] = [];
}
linksByDomain["Other"].push(link);
}
});
// Sort domains alphabetically
const domains = Object.keys(linksByDomain).sort();
// Create link items by domain
domains.forEach((domain, domainIndex) => {
// Add domain header if multiple domains exist
if (domains.length > 1) {
const domainHeader = document.createElement("div");
domainHeader.className = "fc-domain-header";
domainHeader.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<circle cx="12" cy="12" r="4"></circle>
</svg>
<span>${domain}</span>
<span class="fc-domain-count">${linksByDomain[domain].length}</span>
`;
elements.content.appendChild(domainHeader);
}
// Add links for this domain
linksByDomain[domain].forEach(link => {
const linkItem = createLinkItem(link);
elements.content.appendChild(linkItem);
});
});
}
// Create a link item element
function createLinkItem(link) {
const linkItem = document.createElement("div");
linkItem.className = "fc-link-item";
// Link text container
const linkText = document.createElement("a");
linkText.className = "fc-link-text";
linkText.href = link;
linkText.textContent = link;
linkText.title = link;
linkText.rel = "noopener";
linkText.target = "_blank";
// Copy button
const copyBtn = document.createElement("button");
copyBtn.className = "fc-copy-btn";
copyBtn.innerHTML = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
copyBtn.addEventListener('click', (e) => {
e.stopPropagation();
navigator.clipboard.writeText(link)
.then(() => {
// Visual feedback when copied
copyBtn.innerHTML = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 6L9 17l-5-5"></path>
</svg>
`;
setTimeout(() => {
copyBtn.innerHTML = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
`;
}, 1500);
});
});
linkItem.appendChild(linkText);
linkItem.appendChild(copyBtn);
return linkItem;
}