diff --git a/public/app.coffee b/public/app.coffee new file mode 100644 index 0000000..cfc6acc --- /dev/null +++ b/public/app.coffee @@ -0,0 +1,179 @@ +client = new WebTorrent +debug = true + + +app = angular.module 'bTorrent', [], ['$compileProvider','$locationProvider', ($compileProvider, $locationProvider) -> + $compileProvider.aHrefSanitizationWhitelist /^\s*(https?|magnet|blob|javascript):/ + $locationProvider.html5Mode( + enabled: true + requireBase: false).hashPrefix '#' + return +] + +app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', ($scope, $http, $log, $location) -> + $scope.client = client + $scope.seedIt = true + + dbg = (string, torrent) -> + if debug + if torrent + $log.debug '%c' + torrent.name + ' (' + torrent.infoHash + '): %c' + string, 'color: #33C3F0', 'color: #333' + else + $log.debug '%cClient: %c' + string, 'color: #33C3F0', 'color: #333' + return + + updateAll = -> + $scope.$apply() + return + + setInterval updateAll, 500 + + $scope.client.done = -> + done = true + $scope.client.torrents.forEach (torrent) -> + if !torrent.done + done = false + return + done + + $scope.client.downloading = -> + downloading = true + $scope.client.torrents.forEach (torrent) -> + if torrent.done + downloading = false + return + downloading + + $scope.uploadFile = -> + document.getElementById('fileUpload').click() + return + + $scope.uploadFile2 = (elem) -> + $scope.client.processing = true + dbg 'Seeding ' + elem.files[0].name + $scope.client.seed elem.files, $scope.onSeed + return + + $scope.fromInput = -> + if !$scope.torrentInput == '' + $scope.client.processing = true + dbg 'Adding ' + $scope.torrentInput + $scope.client.add $scope.torrentInput, $scope.onTorrent + $scope.torrentInput = '' + return + + $scope.toggleTorrent = (torrent) -> + if torrent.showFiles + torrent.showFiles = false + $scope.sTorrent = null + else + $scope.client.torrents.forEach (t) -> + t.showFiles = false + return + torrent.showFiles = true + $scope.sTorrent = torrent + return + + $scope.destroyedTorrent = (err) -> + if err + throw err + dbg 'Destroyed torrent' + return + + $scope.onTorrent = (torrent, isSeed) -> + $scope.client.processing = false + torrent.showFiles = false + torrent.fileName = torrent.name + '.torrent' + torrent.oTorrentFileURL = torrent.torrentFileURL + if angular.isUndefined($scope.sTorrent) or $scope.sTorrent == null + $scope.sTorrent = torrent + torrent.showFiles = true + + torrent.update = -> + torrent.pProgress = (100 * torrent.progress).toFixed(1) + torrent.pDownloaded = torrent.downloaded + torrent.pUploaded = torrent.uploaded + torrent.pUploadSpeed = torrent.uploadSpeed() + torrent.pDownloadSpeed = torrent.downloadSpeed() + if torrent.done + torrent.tRemaining = 'Done' + else + remaining = moment.duration(torrent.timeRemaining / 1000, 'seconds').humanize() + torrent.tRemaining = remaining[0].toUpperCase() + remaining.substr(1) + return + + torrent.files.forEach (file) -> + file.pSize = file.length + file.status = 'Downloading' + file.url = 'javascript: return false;' + file.getBlobURL (err, url) -> + if err + throw err + file.url = url + if !isSeed + dbg 'Finished downloading file ' + file.name, torrent + file.status = 'Ready' + $scope.$apply() + return + if !isSeed + dbg 'Received file ' + file.name + ' metadata', torrent + return + torrent.on 'download', (chunkSize) -> + if !isSeed + dbg 'Downloaded chunk', torrent + return + torrent.on 'upload', (chunkSize) -> + dbg 'Uploaded chunk', torrent + return + torrent.on 'done', -> + if !isSeed + dbg 'Done', torrent + torrent.update() + return + torrent.on 'wire', (wire, addr) -> + dbg 'Wire ' + addr, torrent + return + setInterval torrent.update, 500 + torrent.update() + return + + $scope.onSeed = (torrent) -> + $scope.onTorrent torrent, true + return + + if $location.hash() != '' + $scope.client.processing = true + dbg 'Adding ' + $location.hash() + client.add $location.hash(), $scope.onTorrent + return +] + +app.filter 'html', ['$sce', ($sce) -> + (input) -> + $sce.trustAsHtml input +] + +app.filter 'pbytes', -> + (num) -> + exponent = undefined + unit = undefined + neg = num < 0 + units = [ + 'B' + 'kB' + 'MB' + 'GB' + 'TB' + 'PB' + 'EB' + 'ZB' + 'YB' + ] + if neg + num = -num + if num < 1 + return (if neg then '-' else '') + num + ' B' + exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1) + num = (num / 1000 ** exponent).toFixed(1) * 1 + unit = units[exponent] + (if neg then '-' else '') + num + ' ' + unit diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100755 index 0000000..1e7aaf5 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.jade b/public/index.jade new file mode 100644 index 0000000..8329652 --- /dev/null +++ b/public/index.jade @@ -0,0 +1,104 @@ +doctype html +html(ng-app='bTorrent', lang='en') + head + base(href='') + meta(charset='UTF-8') + title βTorrent: Browser WebTorrent Client + meta(name='description', content='βTorrent: Browser WebTorrent Client') + meta(name='keywords', content='βTorrent, btorrent, client, webtorrent, browser, torrent') + meta(name='author', content='Diego Rodríguez Baquero - DiegoRBaquero') + meta(name='viewport', content='width=device-width, initial-scale=1') + script(src='https://cdn.jsdelivr.net/g/webtorrent@0.62,momentjs@2.10,angularjs@1.4') + link(rel='stylesheet', href='https://cdn.jsdelivr.net/g/normalize@3.0,skeleton@2.0') + link(rel='stylesheet', href='https://cdn.jsdelivr.net/fontawesome/4.5/css/font-awesome.min.css') + link(rel='stylesheet', href='style.css') + body + header + h1 + | βTorrent + span.version v0.4.1 + .container(ng-controller='bTorrentCtrl', ng-cloak='') + .row + .twelve.columns + .row + .five.columns + input#torrentInput.u-full-width(type='text', placeholder='magnet link or hash', ng-model='torrentInput') + .two.columns + button.button-primary(ng-click='fromInput()') + i.fa.fa-download + | Download + .five.columns.u-pull-right + input#fileUpload(type='file', style='display: none;', onchange='angular.element(this).scope().uploadFile2(this)') + label.u-pull-right + button.button-primary(ng-click='uploadFile()') + i.fa.fa-upload + | Seed a file + table.u-full-width + thead + tr + th Name + th(ng-hide='client.done()') Downloaded + th(ng-hide='client.done()') Remaining + th(ng-hide='client.downloading()') Uploaded + th Peers + th Share + th Actions + tbody(ng-hide='client.torrents.length') + tr + td.center(colspan='100') Add a torrent o seed a file! + tbody(ng-repeat='torrent in client.torrents', ng-if='torrent.name') + tr.torrentRow(ng-class='{selectedTorrent: torrent.showFiles}') + td + div + i.fa.fa-cloud-download(ng-hide='torrent.done') + i.fa.fa-check(ng-show='torrent.done') + | {{torrent.name}} + span.subInfo + | {{torrent.length | pbytes}} in + a(href='#', onclick='return false;', ng-click='toggleTorrent(torrent)') {{torrent.files.length}} files + td(ng-hide='client.done()') + | {{torrent.downloaded | pbytes}} + span.subInfo ({{torrent.pProgress}}%) + br + span.subInfo @ {{torrent.downloadSpeed() | pbytes}}/s + td(ng-hide='client.done()') {{torrent.tRemaining}} + td(ng-hide='client.downloading()') {{torrent.uploaded | pbytes}} + br + span.subInfo @ {{torrent.uploadSpeed() | pbytes}}/s + td {{torrent.swarm.wires.length}} + td + a(href='#{{torrent.infoHash}}', target='_blank') βTorrent + | + a(href='{{torrent.magnetURI}}', target='_blank') Magnet URI + | + a(href='{{torrent.oTorrentFileURL}}', target='_blank', download='{{torrent.fileName}}') .torrent + br + span.subInfo + i.fa.fa-hashtag + | {{torrent.infoHash}} + td + i.fa.fa-times(ng-click='client.remove(torrent, destroyedTorrent)') + tr(ng-show='torrent.showFiles') + td.files(colspan='100') + .row + .two.columns.center + i.fa.fa-file + strong Files: + .ten.columns.fix-height + ul.no-margin + li(ng-repeat='file in torrent.files') + span(ng-hide='file.done') {{file.status}}: {{file.name}} + a(href='{{file.url}}', download='{{file.name}}', target='_blank', ng-show='file.done') {{file.name}} + span.subInfo {{file.length | pbytes}} + tbody(ng-show='client.processing') + tr + td.center(colspan='100') Please wait a few seconds! + footer + | Made in Bogotá, Colombia by + a(href='http://diegorbaquero.com') DiegoRBaquero + br + small + a(href='https://webtorrent.io') WebTorrent + | is powered by JavaScript and WebRTC. Works in Chrome, Firefox, and Opera (desktop and Android). + p + script(src='app.js') diff --git a/public/style.sass b/public/style.sass new file mode 100644 index 0000000..41bef12 --- /dev/null +++ b/public/style.sass @@ -0,0 +1,42 @@ +body + height: 100% + width: 100% + +header, footer, .center + text-align: center + +th, td + padding-left: 10px + padding-right: 10px + max-width: 200px + overflow: scroll + white-space: nowrap + +.version + color: #ccc + font-size: 0.3em + +.torrentRow + line-height: 1.2 + border-bottom: 0 + +.subInfo + color: #bbbbbb + font-size: 0.7em + +.column, .columns + margin-left: 1% + +.files + padding-top: 1px + padding-bottom: 1px + +.fix-height + max-height: 24px + +.no-margin + margin: 0 + +.selectedTorrent + background: rgb(100, 100, 100) + background: rgba(100, 100, 100, 0.06) \ No newline at end of file