diff --git a/index.html b/index.html index 0909cf0..ad03067 100644 --- a/index.html +++ b/index.html @@ -15,5 +15,5 @@

File upload/host

Pastebin

Donate

-

Calculator

-

Games

\ No newline at end of file +

Games

+

Tools

\ No newline at end of file diff --git a/tools/Btorrent/CNAME b/tools/Btorrent/CNAME new file mode 100644 index 0000000..e246f7d --- /dev/null +++ b/tools/Btorrent/CNAME @@ -0,0 +1 @@ +btorrent.xyz \ No newline at end of file diff --git a/tools/Btorrent/LICENSE b/tools/Btorrent/LICENSE new file mode 100644 index 0000000..e1c1ba3 --- /dev/null +++ b/tools/Btorrent/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Diego Rodríguez Baquero + +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. diff --git a/tools/Btorrent/README.md b/tools/Btorrent/README.md new file mode 100644 index 0000000..5be5e46 --- /dev/null +++ b/tools/Btorrent/README.md @@ -0,0 +1,79 @@ +βTorrent +======== +**[βTorrent]** is a fully-featured **[WebTorrent]** browser client written in HTML, JS and CSS + +### Features +- [x] Informative GUI with easy sharing options +- [x] Downloading from an info hash or magnet URI +- [x] Downloading from a .torrent file (Coming Soon) +- [x] Seeding files (Single/multiple files) +- [ ] Seeding CORS-enabled remote files (Coming Soon) +- [x] Download/Upload speed per torrent +- [x] Download/Upload speed of client (All torrents) +- [x] Removing torrents from the client +- [x] Pause/Resume torrent +- [x] Selecting/Deselecting files (Coming Soon) +- [x] Client Debugging +- [ ] Use custom trackers/rtcConfig + +### Built with +- [WebTorrent] +- [AngularJS] +- [Skeleton] +- [Normalize.css] +- [Moment.js] +- [ui-grid] +- [pretty-bytes] +- [ng-file-upload] +- [ng-notify] + +Website powered by [jsDelivr] and [CloudFlare]. I use [nginx] in my server. + +### HTML5 serving +**You must serve index.html as the default** + +For nginx, use this conf: +``` + location / { + try_files $uri$args $uri$args/ /index.html; + } +``` + +### Enable Debugging +Enable βTorrent (Debug logging) and WebTorrent (Logs logging) debug logs by running this in the developer console: +```js +localStorage.debug = '*' +``` +Disable by running this: +```js +localStorage.removeItem('debug') +``` + +### Help βTorrent +- **[Create a new issue](https://github.com/DiegoRBaquero/bTorrent/issues/new)** to report bugs or suggest new features +- **[Send a PR](https://github.com/DiegoRBaquero/BTorrent/pull/new/master)** with your changes + +### Thanks +- [jasalo](https://github.com/jasalo) For the logo and favicon +- [whitef0x0](https://github.com/whitef0x0) For cleanup and ng-file-upload and other ideas + +### License +MIT. Copyright (c) [Diego Rodríguez Baquero](https://diegorbaquero.com) + +[βTorrent]: https://btorrent.xyz +[WebTorrent]: https://webtorrent.io +[AngularJS]: https://angularjs.org/ +[Skeleton]: http://getskeleton.com/ +[Normalize.css]: https://necolas.github.io/normalize.css/ +[Moment.js]: http://momentjs.com/ +[ui-grid]: http://ui-grid.info/ +[pretty-bytes]: https://github.com/sindresorhus/pretty-bytes +[ng-file-upload]: https://github.com/danialfarid/ng-file-upload +[ng-notify]: https://github.com/matowens/ng-notify +[Jade]: http://jade-lang.com/ +[CoffeeScript]: http://coffeescript.org/ +[Sass]: http://sass-lang.com/ +[Harp]: http://harpjs.com/ +[jsDelivr]: https://www.jsdelivr.com/ +[CloudFlare]: https://www.cloudflare.com/ +[nginx]: http://nginx.org/ diff --git a/tools/Btorrent/app.js b/tools/Btorrent/app.js new file mode 100644 index 0000000..c3b648a --- /dev/null +++ b/tools/Btorrent/app.js @@ -0,0 +1,373 @@ +/* global WebTorrent, angular, moment, prompt */ + +const VERSION = '1.1' +const trackers = ['wss://tracker.btorrent.xyz', 'wss://tracker.openwebtorrent.com'] +const rtcConfig = { + 'iceServers': [ + { + 'urls': ['stun:stun.l.google.com:19305', 'stun:stun1.l.google.com:19305'] + } + ] +} + +const torrentOpts = { + announce: trackers +} + +const trackerOpts = { + announce: trackers, + rtcConfig: rtcConfig +} + +const debug = window.localStorage.getItem('debug') !== null + +const dbg = function (string, item, color) { + color = color !== null ? color : '#333333' + if (debug) { + if (item && item.name) { + return console.debug(`%cβTorrent:${item.infoHash !== null ? 'torrent ' : 'torrent ' + item._torrent.name + ':file '}${item.name}${item.infoHash !== null ? ' (' + item.infoHash + ')' : ''} %c${string}`, 'color: #33C3F0', `color: ${color}`) + } else { + return console.debug(`%cβTorrent:client %c${string}`, 'color: #33C3F0', `color: ${color}`) + } + } +} + +const er = function (err, item) { dbg(err, item, '#FF0000') } + +dbg(`Starting v${VERSION}. WebTorrent ${WebTorrent.VERSION}`) + +const client = new WebTorrent({ + tracker: trackerOpts +}) + +const app = angular.module('BTorrent', + ['ngRoute', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.selection', 'ngFileUpload', 'ngNotify'], + ['$compileProvider', '$locationProvider', '$routeProvider', function ($compileProvider, $locationProvider, $routeProvider) { + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|magnet|blob|javascript):/) + $locationProvider.html5Mode({ + enabled: true, + requireBase: false + }).hashPrefix('#') + $routeProvider.when('/view', { + templateUrl: 'views/view.html', + controller: 'ViewCtrl' + }).when('/download', { + templateUrl: 'views/download.html', + controller: 'DownloadCtrl' + }).otherwise({ + templateUrl: 'views/full.html', + controller: 'FullCtrl' + }) + }] +) + +app.controller('BTorrentCtrl', ['$scope', '$rootScope', '$http', '$log', '$location', 'ngNotify', function ($scope, $rootScope, $http, $log, $location, ngNotify) { + let updateAll + $rootScope.version = VERSION + $rootScope.webtorrentVersion = WebTorrent.VERSION + ngNotify.config({ + duration: 5000, + html: true + }) + if (!WebTorrent.WEBRTC_SUPPORT) { + $rootScope.disabled = true + ngNotify.set('Please use a WebRTC compatible browser', { + type: 'error', + sticky: true, + button: false + }) + } + $rootScope.client = client + updateAll = function () { + if ($rootScope.client.processing) { + return + } + $rootScope.$apply() + } + setInterval(updateAll, 500) + $rootScope.seedFiles = function (files) { + let name + if ((files != null) && files.length > 0) { + if (files.length === 1) { + dbg(`Seeding file ${files[0].name}`) + } else { + dbg(`Seeding ${files.length} files`) + name = prompt('Please name your torrent', 'My Awesome Torrent') || 'My Awesome Torrent' + torrentOpts.name = name + } + $rootScope.client.processing = true + $rootScope.client.seed(files, torrentOpts, $rootScope.onSeed) + delete torrentOpts.name + } + } + $rootScope.openTorrentFile = function (file) { + if (file != null) { + dbg(`Adding torrent file ${file.name}`) + $rootScope.client.processing = true + $rootScope.client.add(file, torrentOpts, $rootScope.onTorrent) + } + } + $rootScope.client.on('error', function (err, torrent) { + $rootScope.client.processing = false + ngNotify.set(err, 'error') + er(err, torrent) + }) + $rootScope.addMagnet = function (magnet, onTorrent) { + if ((magnet != null) && magnet.length > 0) { + dbg(`Adding magnet/hash ${magnet}`) + $rootScope.client.processing = true + $rootScope.client.add(magnet, torrentOpts, onTorrent || $rootScope.onTorrent) + } + } + $rootScope.destroyedTorrent = function (err) { + if (err) { + throw err + } + dbg('Destroyed torrent', $rootScope.selectedTorrent) + $rootScope.selectedTorrent = null + $rootScope.client.processing = false + } + $rootScope.changePriority = function (file) { + if (file.priority === '-1') { + dbg('Deselected', file) + file.deselect() + } else { + dbg(`Selected with priority ${file.priority}`, file) + file.select(file.priority) + } + } + $rootScope.onTorrent = function (torrent, isSeed) { + dbg(torrent.magnetURI) + torrent.safeTorrentFileURL = torrent.torrentFileBlobURL + torrent.fileName = `${torrent.name}.torrent` + if (!isSeed) { + dbg('Received metadata', torrent) + ngNotify.set(`Received ${torrent.name} metadata`) + if (!($rootScope.selectedTorrent != null)) { + $rootScope.selectedTorrent = torrent + } + $rootScope.client.processing = false + } + torrent.files.forEach(function (file) { + file.getBlobURL(function (err, url) { + if (err) { + throw err + } + if (isSeed) { + dbg('Started seeding', torrent) + if (!($rootScope.selectedTorrent != null)) { + $rootScope.selectedTorrent = torrent + } + $rootScope.client.processing = false + } + file.url = url + if (!isSeed) { + dbg('Done ', file) + ngNotify.set(`${file.name} ready for download`, 'success') + } + }) + }) + torrent.on('done', function () { + if (!isSeed) { + dbg('Done', torrent) + } + ngNotify.set(`${torrent.name} has finished downloading`, 'success') + }) + torrent.on('wire', function (wire, addr) { dbg(`Wire ${addr}`, torrent) }) + torrent.on('error', er) + } + $rootScope.onSeed = function (torrent) { $rootScope.onTorrent(torrent, true) } + dbg('Ready') +} +]) + +app.controller('FullCtrl', ['$scope', '$rootScope', '$http', '$log', '$location', 'ngNotify', function ($scope, $rootScope, $http, $log, $location, ngNotify) { + ngNotify.config({ + duration: 5000, + html: true + }) + $scope.addMagnet = function () { + $rootScope.addMagnet($scope.torrentInput) + $scope.torrentInput = '' + } + $scope.columns = [ + { + field: 'name', + cellTooltip: true, + minWidth: '200' + }, { + field: 'length', + name: 'Size', + cellFilter: 'pbytes', + width: '80' + }, { + field: 'received', + displayName: 'Downloaded', + cellFilter: 'pbytes', + width: '135' + }, { + field: 'downloadSpeed', + displayName: '↓ Speed', + cellFilter: 'pbytes:1', + width: '100' + }, { + field: 'progress', + displayName: 'Progress', + cellFilter: 'progress', + width: '100' + }, { + field: 'timeRemaining', + displayName: 'ETA', + cellFilter: 'humanTime', + width: '140' + }, { + field: 'uploaded', + displayName: 'Uploaded', + cellFilter: 'pbytes', + width: '125' + }, { + field: 'uploadSpeed', + displayName: '↑ Speed', + cellFilter: 'pbytes:1', + width: '100' + }, { + field: 'numPeers', + displayName: 'Peers', + width: '80' + }, { + field: 'ratio', + cellFilter: 'number:2', + width: '80' + } + ] + $scope.gridOptions = { + columnDefs: $scope.columns, + data: $rootScope.client.torrents, + enableColumnResizing: true, + enableColumnMenus: false, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false + } + $scope.gridOptions.onRegisterApi = function (gridApi) { + $scope.gridApi = gridApi + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + if (!row.isSelected && ($rootScope.selectedTorrent != null) && ($rootScope.selectedTorrent.infoHash = row.entity.infoHash)) { + $rootScope.selectedTorrent = null + } else { + $rootScope.selectedTorrent = row.entity + } + }) + } + if ($location.hash() !== '') { + $rootScope.client.processing = true + setTimeout(function () { + dbg(`Adding ${$location.hash()}`) + $rootScope.addMagnet($location.hash()) + }, 0) + } +} +]) + +app.controller('DownloadCtrl', ['$scope', '$rootScope', '$http', '$log', '$location', 'ngNotify', function ($scope, $rootScope, $http, $log, $location, ngNotify) { + ngNotify.config({ + duration: 5000, + html: true + }) + $scope.addMagnet = function () { + $rootScope.addMagnet($scope.torrentInput) + $scope.torrentInput = '' + } + if ($location.hash() !== '') { + $rootScope.client.processing = true + setTimeout(function () { + dbg(`Adding ${$location.hash()}`) + $rootScope.addMagnet($location.hash()) + }, 0) + } +} +]) + +app.controller('ViewCtrl', ['$scope', '$rootScope', '$http', '$log', '$location', 'ngNotify', function ($scope, $rootScope, $http, $log, $location, ngNotify) { + let onTorrent + ngNotify.config({ + duration: 2000, + html: true + }) + onTorrent = function (torrent) { + $rootScope.viewerStyle = { + 'margin-top': '-20px', + 'text-align': 'center' + } + dbg(torrent.magnetURI) + torrent.safeTorrentFileURL = torrent.torrentFileBlobURL + torrent.fileName = `${torrent.name}.torrent` + $rootScope.selectedTorrent = torrent + $rootScope.client.processing = false + dbg('Received metadata', torrent) + ngNotify.set(`Received ${torrent.name} metadata`) + torrent.files.forEach(function (file) { + file.appendTo('#viewer') + file.getBlobURL(function (err, url) { + if (err) { + throw err + } + file.url = url + dbg('Done ', file) + }) + }) + torrent.on('done', function () { dbg('Done', torrent) }) + torrent.on('wire', function (wire, addr) { dbg(`Wire ${addr}`, torrent) }) + torrent.on('error', er) + } + $scope.addMagnet = function () { + $rootScope.addMagnet($scope.torrentInput, onTorrent) + $scope.torrentInput = '' + } + if ($location.hash() !== '') { + $rootScope.client.processing = true + setTimeout(function () { + dbg(`Adding ${$location.hash()}`) + $rootScope.addMagnet($location.hash(), onTorrent) + }, 0) + } +} +]) + +app.filter('html', [ + '$sce', function ($sce) { + return function (input) { + $sce.trustAsHtml(input) + } + } +]) + +app.filter('pbytes', function () { + return function (num, speed) { + let exponent, unit, units + if (isNaN(num)) { + return '' + } + units = ['B', 'kB', 'MB', 'GB', 'TB'] + if (num < 1) { + return (speed ? '' : '0 B') + } + exponent = Math.min(Math.floor(Math.log(num) / 6.907755278982137), 8) + num = (num / Math.pow(1000, exponent)).toFixed(1) * 1 + unit = units[exponent] + return `${num} ${unit}${speed ? '/s' : ''}` + } +}) + +app.filter('humanTime', function () { + return function (millis) { + let remaining + if (millis < 1000) { + return '' + } + remaining = moment.duration(millis).humanize() + return remaining[0].toUpperCase() + remaining.substr(1) + } +}) + +app.filter('progress', function () { return function (num) { return `${(100 * num).toFixed(1)}%` } }) diff --git a/tools/Btorrent/favicon.ico b/tools/Btorrent/favicon.ico new file mode 100644 index 0000000..2e58017 Binary files /dev/null and b/tools/Btorrent/favicon.ico differ diff --git a/tools/Btorrent/index.html b/tools/Btorrent/index.html new file mode 100644 index 0000000..4700e08 --- /dev/null +++ b/tools/Btorrent/index.html @@ -0,0 +1,36 @@ + + + + + + βTorrent: Browser WebTorrent Client + + + + + + + + + + + +
+

βTorrent v{{$root.version}}

+
Full | Single Download | Stream / View
+
+
+
+
+
+ +
+ + + diff --git a/tools/Btorrent/style.css b/tools/Btorrent/style.css new file mode 100644 index 0000000..caec711 --- /dev/null +++ b/tools/Btorrent/style.css @@ -0,0 +1,87 @@ +body { + height: 100%; + width: 100%; } + +header, footer, .center { + text-align: center; } + +th, td { + padding: 2px 15px; + max-width: 200px; + overflow: auto; + white-space: nowrap; } + +h2, h3, h4, h5, h6, ul, li { + margin-bottom: 0; } + +footer { + margin-top: 10px; } + +.container { + width: 95%; + max-width: 95%; } + +.grid { + margin-bottom: 20px; + width: 100%; + height: 200px; } + +.version { + color: #ccc; + font-size: 0.3em; } + +.views { + margin-top: -20px; + margin-bottom: 10px; } + +.download-button { + margin-left: 10px; } + +.no-margin { + margin: 0px; } + +.spinner { + position: absolute; + top: 30%; + left: 30%; + width: 40%; + height: 40%; + z-index: 1000; + background-color: grey; + border-radius: 25px; + opacity: .8; + text-align: center; } + +.spinner-icon { + position: relative; + top: 50%; + margin-top: -100px; + font-size: 200px; + transform: translateY(-50%); } + +.button.button-danger, +button.button-danger, +input[type="submit"].button-danger, +input[type="reset"].button-danger, +input[type="button"].button-danger { + color: #FFF; + background-color: #D9534F; + border-color: #D9534F; } + +.button.button-danger:hover, +button.button-danger:hover, +input[type="submit"].button-danger:hover, +input[type="reset"].button-danger:hover, +input[type="button"].button-danger:hover, +.button.button-danger:focus, +button.button-danger:focus, +input[type="submit"].button-danger:focus, +input[type="reset"].button-danger:focus, +input[type="button"].button-danger:focus { + color: #FFF; + background-color: #C43E3A; + border-color: #C43E3A; } + +a { + text-decoration: none +} diff --git a/tools/Btorrent/views/download.html b/tools/Btorrent/views/download.html new file mode 100644 index 0000000..fde09c1 --- /dev/null +++ b/tools/Btorrent/views/download.html @@ -0,0 +1,88 @@ + +
+
+
+
+ + +
+ +
+
+ + +
+
+
+
+

Information

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{{$root.selectedTorrent.name}}
Size{{$root.selectedTorrent.length | pbytes}}
Completed{{$root.selectedTorrent.progress | progress}} ({{$root.selectedTorrent.downloaded | pbytes}})
Peers{{$root.selectedTorrent.numPeers}}
↓ Speed{{$root.selectedTorrent.downloadSpeed | pbytes:1}}
ETA{{$root.selectedTorrent.timeRemaining | humanTime}}
+
+
+

Files

+ + + + + + + + + + + + + + + + +
NameSizePriority
{{file.name}}{{file.name}}{{file.length | pbytes}} + +
+
↑ Click a file to download it
+
+
+

Share

+ +
+
+
\ No newline at end of file diff --git a/tools/Btorrent/views/full.html b/tools/Btorrent/views/full.html new file mode 100644 index 0000000..2d094ec --- /dev/null +++ b/tools/Btorrent/views/full.html @@ -0,0 +1,64 @@ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
{{$root.selectedTorrent.name}} + + + +
+
Share
+ +
+
+
Files
+ + + + + + + + + + + + + + + + +
NameSizePriority
{{file.name}}{{file.name}}{{file.length | pbytes}} + +
+
+
+
Client Stats: + ↓ {{$root.client.downloadSpeed | pbytes}}/s · + ↑ {{$root.client.uploadSpeed | pbytes}}/s · + Ratio: {{$root.client.ratio | number:2}}
+
\ No newline at end of file diff --git a/tools/Btorrent/views/view.html b/tools/Btorrent/views/view.html new file mode 100644 index 0000000..040a902 --- /dev/null +++ b/tools/Btorrent/views/view.html @@ -0,0 +1,20 @@ + +
+
+
+
+ + +
+ +
+
+ + +
+
+
Downloaded {{$root.selectedTorrent.downloaded | pbytes}}/{{$root.selectedTorrent.length | pbytes}} ({{$root.selectedTorrent.progress | progress}}) at {{$root.selectedTorrent.downloadSpeed | pbytes:1}} from {{$root.selectedTorrent.numPeers}} peers. ETA: {{$root.selectedTorrent.timeRemaining | humanTime}}
+
\ No newline at end of file diff --git a/tools/index.html b/tools/index.html new file mode 100644 index 0000000..86c61db --- /dev/null +++ b/tools/index.html @@ -0,0 +1,3 @@ +

Calculator

+

Online torrent downloader/seeder

+

Chat app made with scratch's cloud variable system

\ No newline at end of file