Redirect Scribd document pages to embed URLs dengan tombol download PDF yang interaktif dan multiple access keys
// ==UserScript==
// @name Scribd Downloader
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Redirect Scribd document pages to embed URLs dengan tombol download PDF yang interaktif dan multiple access keys
// @author youcantrust
// @match *://*.scribd.com/*
// @match *://scribd.com/*
// @run-at document-start
// @grant GM_xmlhttpRequest
// @grant GM_download
// @grant GM_setValue
// @grant GM_getValue
// @connect *
// @license MIT
// Copyright (c) [year] [fullname]
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ==/UserScript==
(function() {
'use strict';
// Multiple access keys untuk fallback
const accessKeys = [
'key-ixxYfpwtHw5XUehk3QyF'
];
// Fungsi untuk mendapatkan access key secara acak
function getRandomAccessKey() {
return accessKeys[Math.floor(Math.random() * accessKeys.length)];
}
// Fungsi untuk mengekstrak ID dari berbagai format URL Scribd
function extractDocumentId(url) {
if (url.includes('/embeds/')) {
const embedMatch = url.match(/\/embeds\/([^\/\?&]+)/);
if (embedMatch && embedMatch[1]) {
return embedMatch[1];
}
}
const patterns = [
/\/(?:document|doc)\/([^\/\?&]+)/,
/\/(?:read|pub)\/([^\/\?&]+)/,
/\/(\d{8,})/,
/\/(\d+)-[^\/\?&]+/,
/\/(\d+)(?:\?|$|\/)/,
/\/([a-zA-Z0-9_-]{8,})(?:\?|$|\/)/,
/(?:\?|&)id=([^&]+)/,
/(?:\?|&)document_id=([^&]+)/,
/(?:\?|&)doc_id=([^&]+)/
];
for (let pattern of patterns) {
const match = url.match(pattern);
if (match && match[1]) {
const potentialId = match[1];
if (/^\d+$/.test(potentialId) && potentialId.length >= 6) {
return potentialId;
}
if (/^[a-zA-Z0-9_-]+$/.test(potentialId) && potentialId.length >= 6) {
return potentialId;
}
}
}
return null;
}
// Fungsi untuk menambahkan CSS animasi
function addStyles() {
const styles = `
@keyframes pulse-glow {
0% { box-shadow: 0 0 5px #ff4444, 0 0 10px #ff4444; }
50% { box-shadow: 0 0 20px #ff4444, 0 0 30px #ff4444; }
100% { box-shadow: 0 0 5px #ff4444, 0 0 10px #ff4444; }
}
@keyframes shake {
0%, 100% { transform: translateX(0) scale(1.1); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px) scale(1.1); }
20%, 40%, 60%, 80% { transform: translateX(5px) scale(1.1); }
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0) scale(1.1); }
40% { transform: translateY(-10px) scale(1.1); }
60% { transform: translateY(-5px) scale(1.1); }
}
@keyframes float {
0%, 100% { transform: translateY(0) scale(1.1); }
50% { transform: translateY(-5px) scale(1.1); }
}
@keyframes rainbow {
0% { background: linear-gradient(45deg, #ff0000, #ff4444); }
25% { background: linear-gradient(45deg, #ff4444, #ff8800); }
50% { background: linear-gradient(45deg, #ff8800, #ffaa00); }
75% { background: linear-gradient(45deg, #ffaa00, #ff4444); }
100% { background: linear-gradient(45deg, #ff4444, #ff0000); }
}
.download-btn {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
background: linear-gradient(45deg, #ff4444, #ff0000);
color: white;
border: none;
padding: 15px 25px;
border-radius: 50px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 15px rgba(255, 0, 0, 0.4);
transition: all 0.3s ease;
transform: scale(1.1);
animation: pulse-glow 2s infinite, shake 3s 3s infinite, float 3s 6s infinite;
}
.download-btn:hover {
animation: none;
transform: scale(1.2);
background: linear-gradient(45deg, #ff0000, #cc0000);
box-shadow: 0 6px 20px rgba(255, 0, 0, 0.6);
}
.download-btn:active {
transform: scale(1.15);
}
.download-btn.rainbow {
animation: rainbow 3s infinite, bounce 2s infinite !important;
}
.download-btn.loading {
animation: pulse-glow 1s infinite !important;
background: linear-gradient(45deg, #ff8800, #ffaa00) !important;
}
.download-btn.success {
animation: none !important;
background: linear-gradient(45deg, #00cc00, #00aa00) !important;
transform: scale(1.1);
}
.download-btn.error {
animation: shake 0.5s infinite !important;
background: linear-gradient(45deg, #cc0000, #990000) !important;
}
.download-pulse {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.3);
border-radius: 50px;
transform: translate(-50%, -50%);
animation: ripple 2s infinite;
}
@keyframes ripple {
0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; }
}
`;
const styleSheet = document.createElement('style');
styleSheet.textContent = styles;
document.head.appendChild(styleSheet);
}
// Fungsi untuk membuat tombol download PDF yang sangat interaktif
function createDownloadButton(documentId) {
addStyles();
const button = document.createElement('button');
button.className = 'download-btn';
button.innerHTML = '📥 DOWNLOAD PDF';
// Tambahkan elemen untuk efek ripple
const pulse = document.createElement('div');
pulse.className = 'download-pulse';
button.appendChild(pulse);
// Efek hover
button.addEventListener('mouseenter', function() {
this.classList.add('rainbow');
});
button.addEventListener('mouseleave', function() {
this.classList.remove('rainbow');
});
// Klik handler
button.addEventListener('click', function() {
this.classList.remove('rainbow');
this.classList.add('loading');
this.innerHTML = '⏳ MENGUNDUH...';
// Hapus efek pulse saat loading
const existingPulse = this.querySelector('.download-pulse');
if (existingPulse) {
existingPulse.remove();
}
downloadAsPDF(documentId, button);
});
// Rotasi animasi setiap 10 detik
let animationIndex = 0;
const animations = ['shake', 'bounce', 'float'];
setInterval(() => {
if (!button.classList.contains('loading') &&
!button.classList.contains('success') &&
!button.classList.contains('error')) {
// Hapus semua class animasi
animations.forEach(anim => button.style.animation = '');
// Setel animasi baru
setTimeout(() => {
if (!button.classList.contains('loading') &&
!button.classList.contains('success') &&
!button.classList.contains('error')) {
button.style.animation = `pulse-glow 2s infinite, ${animations[animationIndex]} 3s infinite`;
}
}, 100);
animationIndex = (animationIndex + 1) % animations.length;
}
}, 10000);
return button;
}
// Fungsi untuk mendownload sebagai PDF dengan multiple access keys
function downloadAsPDF(documentId, button) {
let currentKeyIndex = 0;
function tryDownloadWithKey() {
if (currentKeyIndex >= accessKeys.length) {
// Semua access keys sudah dicoba, coba endpoint tanpa access key
tryDirectDownload();
return;
}
const accessKey = accessKeys[currentKeyIndex];
const endpoints = [
`https://scribd.com/embeds/${documentId}/content?format=pdf&access_key=${accessKey}`,
`https://scribd.com/doc/${documentId}/download?format=pdf&access_key=${accessKey}`,
`https://scribd.com/document/${documentId}/download?format=pdf&access_key=${accessKey}`,
`https://scribd.com/embeds/${documentId}/download?format=pdf&access_key=${accessKey}`
];
let currentEndpoint = 0;
function tryDownload() {
if (currentEndpoint >= endpoints.length) {
// Coba access key berikutnya
currentKeyIndex++;
setTimeout(tryDownloadWithKey, 500);
return;
}
const endpoint = endpoints[currentEndpoint];
console.log(`Mencoba mengunduh dari: ${endpoint}`);
GM_xmlhttpRequest({
method: 'GET',
url: endpoint,
responseType: 'blob',
onload: function(response) {
if (response.status === 200) {
const blob = response.response;
const url = URL.createObjectURL(blob);
const filename = `scribd_${documentId}_${new Date().getTime()}.pdf`;
GM_download({
url: url,
name: filename,
onload: function() {
button.classList.remove('loading');
button.classList.add('success');
button.innerHTML = '✅ BERHASIL!';
setTimeout(() => {
button.classList.remove('success');
button.innerHTML = '📥 DOWNLOAD PDF';
// Tambahkan kembali efek pulse
const pulse = document.createElement('div');
pulse.className = 'download-pulse';
button.appendChild(pulse);
}, 3000);
URL.revokeObjectURL(url);
},
onerror: function() {
currentEndpoint++;
setTimeout(tryDownload, 500);
}
});
} else {
currentEndpoint++;
setTimeout(tryDownload, 500);
}
},
onerror: function() {
currentEndpoint++;
setTimeout(tryDownload, 500);
},
ontimeout: function() {
currentEndpoint++;
setTimeout(tryDownload, 500);
}
});
}
tryDownload();
}
// Fallback: coba download tanpa access key
function tryDirectDownload() {
const directEndpoints = [
`https://scribd.com/embeds/${documentId}/content?format=pdf`,
`https://scribd.com/doc/${documentId}/download?format=pdf`,
`https://scribd.com/document/${documentId}/download?format=pdf`,
`https://scribd.com/embeds/${documentId}/download?format=pdf`
];
let currentDirectEndpoint = 0;
function tryDirect() {
if (currentDirectEndpoint >= directEndpoints.length) {
// Semua endpoint gagal
showError();
return;
}
const endpoint = directEndpoints[currentDirectEndpoint];
console.log(`Mencoba mengunduh tanpa access key dari: ${endpoint}`);
GM_xmlhttpRequest({
method: 'GET',
url: endpoint,
responseType: 'blob',
onload: function(response) {
if (response.status === 200) {
const blob = response.response;
const url = URL.createObjectURL(blob);
const filename = `scribd_${documentId}_${new Date().getTime()}.pdf`;
GM_download({
url: url,
name: filename,
onload: function() {
button.classList.remove('loading');
button.classList.add('success');
button.innerHTML = '✅ BERHASIL!';
setTimeout(() => {
button.classList.remove('success');
button.innerHTML = '📥 DOWNLOAD PDF';
const pulse = document.createElement('div');
pulse.className = 'download-pulse';
button.appendChild(pulse);
}, 3000);
URL.revokeObjectURL(url);
},
onerror: function() {
currentDirectEndpoint++;
setTimeout(tryDirect, 500);
}
});
} else {
currentDirectEndpoint++;
setTimeout(tryDirect, 500);
}
},
onerror: function() {
currentDirectEndpoint++;
setTimeout(tryDirect, 500);
},
ontimeout: function() {
currentDirectEndpoint++;
setTimeout(tryDirect, 500);
}
});
}
function showError() {
button.classList.remove('loading');
button.classList.add('error');
button.innerHTML = '❌ GAGAL MENGUNDH';
setTimeout(() => {
button.classList.remove('error');
button.innerHTML = '📥 DOWNLOAD PDF';
// Tambahkan kembali efek pulse
const pulse = document.createElement('div');
pulse.className = 'download-pulse';
button.appendChild(pulse);
}, 5000);
}
tryDirect();
}
tryDownloadWithKey();
}
// Fungsi untuk menambahkan tombol ke halaman
function addDownloadButtonToPage(documentId) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(() => {
const existingButton = document.querySelector('.download-btn');
if (!existingButton) {
const button = createDownloadButton(documentId);
document.body.appendChild(button);
// Tambahkan efek muncul dengan animasi
setTimeout(() => {
button.style.opacity = '0';
button.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
button.style.opacity = '1';
}, 100);
}, 100);
}
}, 3000);
});
} else {
setTimeout(() => {
const existingButton = document.querySelector('.download-btn');
if (!existingButton) {
const button = createDownloadButton(documentId);
document.body.appendChild(button);
// Tambahkan efek muncul dengan animasi
setTimeout(() => {
button.style.opacity = '0';
button.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
button.style.opacity = '1';
}, 100);
}, 100);
}
}, 3000);
}
}
// Fungsi untuk memeriksa apakah URL saat ini menggunakan salah satu access key yang valid
function isValidEmbedUrl(url) {
return accessKeys.some(key => url.includes(key));
}
// Main logic
const currentUrl = window.location.href;
// Cek jika kita sudah di embed URL dengan access key yang valid
if (currentUrl.includes('/embeds/') && isValidEmbedUrl(currentUrl)) {
const documentId = extractDocumentId(currentUrl);
if (documentId) {
console.log('Document ID ditemukan:', documentId);
addDownloadButtonToPage(documentId);
}
return;
}
// Jika bukan di embed URL yang valid, lakukan redirect dengan access key acak
const documentId = extractDocumentId(currentUrl);
if (documentId && !currentUrl.includes('/embeds/')) {
const randomAccessKey = getRandomAccessKey();
const embedUrl = `https://scribd.com/embeds/${documentId}/content?start_page=1&view_mode=scroll&access_key=${randomAccessKey}`;
console.log(`Redirecting from: ${currentUrl}`);
console.log(`Document ID found: ${documentId}`);
console.log(`Using access key: ${randomAccessKey}`);
console.log(`Redirecting to: ${embedUrl}`);
window.location.replace(embedUrl);
}
})();