diff --git a/app.coffee b/app.coffee index c190ea6..8e0cf6e 100644 --- a/app.coffee +++ b/app.coffee @@ -11,81 +11,86 @@ trackers = [ opts = {announce: trackers} client = new WebTorrent -debug = window.localStorage ? window.localStorage.getItem('debug') == '*':false -app = angular.module 'bTorrent', [], ['$compileProvider','$locationProvider', ($compileProvider, $locationProvider) -> +dbg = (string, torrent) -> + if (window.localStorage ? window.localStorage.getItem('debug') == '*':false) + if torrent + console.debug '%c' + torrent.name + ' (' + torrent.infoHash + '): %c' + string, 'color: #33C3F0', 'color: #333' + return + else + console.debug '%cClient: %c' + string, 'color: #33C3F0', 'color: #333' + return + return + +app = angular.module 'bTorrent', ['ui.grid', 'ui.grid.resizeColumns', 'ui.grid.selection'], ['$compileProvider','$locationProvider', ($compileProvider, $locationProvider) -> $compileProvider.aHrefSanitizationWhitelist /^\s*(https?|magnet|blob|javascript):/ $locationProvider.html5Mode( enabled: true requireBase: false).hashPrefix '#' ] -app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', ($scope, $http, $log, $location) -> +app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', 'uiGridConstants', ($scope, $http, $log, $location, uiGridConstants) -> $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' - return - else - $log.debug '%cClient: %c' + string, 'color: #33C3F0', 'color: #333' - return - return + + $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: '150'} + {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: $scope.client.torrents + enableColumnResizing: true + enableColumnMenus: false + enableRowSelection: true + enableRowHeaderSelection: false + multiSelect: false updateAll = -> + if $scope.client.processing + return $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.gridOptions.onRegisterApi = ( gridApi ) -> + $scope.gridApi = gridApi + gridApi.selection.on.rowSelectionChanged $scope, (row) -> + if !row.isSelected && $scope.selectedTorrent? && $scope.selectedTorrent.infoHash = row.entity.infoHash + $scope.selectedTorrent = null + else + $scope.selectedTorrent = row.entity $scope.uploadFile = -> document.getElementById('fileUpload').click() return $scope.uploadFile2 = (elem) -> - $scope.client.processing = true dbg 'Seeding ' + elem.files[0].name + $scope.client.processing = true + $scope.$apply() $scope.client.seed elem.files, opts, $scope.onSeed return $scope.fromInput = -> if $scope.torrentInput != '' - $scope.client.processing = true dbg 'Adding ' + $scope.torrentInput + $scope.client.processing = true + $scope.$apply() $scope.client.add $scope.torrentInput, opts, $scope.onTorrent $scope.torrentInput = '' return - $scope.toggleTorrent = (torrent) -> - if torrent.showFiles - torrent.showFiles = false - $scope.sTorrent = null - return - else - $scope.client.torrents.forEach (t) -> - t.showFiles = false - torrent.showFiles = true - $scope.sTorrent = torrent - return - $scope.destroyedTorrent = (err) -> $scope.client.processing = false if err @@ -94,39 +99,24 @@ app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', ($scope, $h return $scope.onTorrent = (torrent, isSeed) -> - if !isSeed - $scope.client.processing = false - torrent.pSize = torrent.length - torrent.showFiles = false + torrent.safeTorrentFileURL = torrent.torrentFileURL 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) - if torrent.done - torrent.tRemaining = 'Done' - return - else - remaining = moment.duration(torrent.timeRemaining / 1000, 'seconds').humanize() - torrent.tRemaining = remaining[0].toUpperCase() + remaining.substr(1) - return + + if !isSeed + $scope.client.processing = false + if !($scope.selectedTorrent?) + $scope.selectedTorrent = torrent torrent.files.forEach (file) -> - file.pSize = file.length - file.status = 'Downloading' - file.url = 'javascript: return false;' file.getBlobURL (err, url) -> if err throw err if isSeed $scope.client.processing = false + $scope.$apply() file.url = url if !isSeed dbg 'Finished downloading file ' + file.name, torrent - file.status = 'Ready' return if !isSeed dbg 'Received file ' + file.name + ' metadata', torrent @@ -147,8 +137,6 @@ app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', ($scope, $h torrent.on 'wire', (wire, addr) -> dbg 'Wire ' + addr, torrent return - setInterval torrent.update, 500 - torrent.update() return $scope.onSeed = (torrent) -> $scope.onTorrent torrent, true @@ -156,8 +144,10 @@ app.controller 'bTorrentCtrl', ['$scope','$http','$log','$location', ($scope, $h if $location.hash() != '' $scope.client.processing = true - dbg 'Adding ' + $location.hash() - client.add $location.hash(), $scope.onTorrent + setTimeout -> + dbg 'Adding ' + $location.hash() + $scope.client.add $location.hash(), $scope.onTorrent + , 500 return ] @@ -168,28 +158,32 @@ app.filter 'html', ['$sce', ($sce) -> ] app.filter 'pbytes', -> - (num) -> + (num, speed) -> if isNaN(num) return '' 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' + return (if speed then '' else '0 B') exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), 8) num = (num / 1000 ** exponent).toFixed(1) * 1 unit = units[exponent] - (if neg then '-' else '') + num + ' ' + unit + num + ' ' + unit + (if speed then '/s' else '') + +app.filter 'humanTime', -> + (millis) -> + if millis < 1000 + return '' + remaining = moment.duration(millis / 1000, 'seconds').humanize() + remaining[0].toUpperCase() + remaining.substr(1) + +app.filter 'progress', -> + (num) -> + (100 * num).toFixed(1) + '%' \ No newline at end of file diff --git a/index.jade b/index.jade index b32b506..1468f84 100644 --- a/index.jade +++ b/index.jade @@ -8,102 +8,76 @@ html(ng-app='bTorrent', lang='en') meta(name='keywords', content='βTorrent, btorrent, client, webtorrent, browser, torrent, stream, bittorrent') 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') + script(src='https://cdn.jsdelivr.net/g/webtorrent@0.63.1,momentjs@2.10,angularjs@1.4,angular.ui-grid@3.0.7') 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='https://cdn.jsdelivr.net/angular.ui-grid/3.0.7/ui-grid.min.css') link(rel='stylesheet', href='style.css') - body + body(ng-controller='bTorrentCtrl', ng-cloak='') header h1 | βTorrent - span.version v0.5.03 - .container(ng-controller='bTorrentCtrl', ng-cloak='') + span.version v0.6 + + .container .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 + .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 + .row.grid(ui-grid='gridOptions', ui-grid-resize-columns, ui-grid-selection) + .row(ng-if="selectedTorrent") + .six.columns + h4 {{selectedTorrent.name}} + h5 Share + ul + li + a(ng-href='#{{selectedTorrent.infoHash}}', target='_blank') βTorrent + li + a(ng-href='{{selectedTorrent.magnetURI}}', target='_blank') Magnet URI + li + a(ng-href='{{selectedTorrent.safeTorrentFileURL}}', target='_blank', download='{{torrent.fileName}}') .torrent + li + strong Hash: + | {{selectedTorrent.infoHash}} + .six.columns + h4 Files 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 or 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.pSize | 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(ng-href='#{{torrent.infoHash}}', target='_blank') - | βTorrent - | - a(ng-href='{{torrent.magnetURI}}', target='_blank') - | Magnet URI - | - a(ng-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.processing = true; 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.pSize | pbytes}} - tbody(ng-show='client.processing') - tr - td.center(colspan='100') Please wait a few seconds! + th Size + tbody + tr.files(ng-repeat='file in selectedTorrent.files') + td(ng-hide='file.done') {{file.name}} + td(ng-show='file.done') + a(ng-href='{{file.url}}', download='{{file.name}}', target='_blank', ng-show='file.done') {{file.name}} + td {{file.length | pbytes}} + hr footer + a.button(href="https://github.com/DiegoRBaquero/BTorrent", target="_blank") View on GitHub + i.fa.fa-github + | + a.button(href="https://github.com/DiegoRBaquero/BTorrent/issues", target="_blank") Suggest a new feature / Report a bug + i.fa.comment + | + a.button(href="https://github.com/DiegoRBaquero/BTorrent/fork", target="_blank") Fork me + i.fa.fa-code-fork + br | Made in Bogotá, Colombia by a(href='http://diegorbaquero.com') DiegoRBaquero br - small - | Powered by - a(href='https://webtorrent.io') WebTorrent + | Powered by + a(href='https://webtorrent.io') WebTorrent p - script(src='app.js') + .spinner(ng-show="client.processing") + i.fa.fa-spinner.fa-6.fa-spin.spinner-icon + script(src='app.js') \ No newline at end of file diff --git a/style.sass b/style.sass index 6e1f6b0..099c5cc 100644 --- a/style.sass +++ b/style.sass @@ -6,37 +6,45 @@ header, footer, .center text-align: center th, td - padding-left: 10px - padding-right: 10px + padding: 2px 15px max-width: 200px overflow: auto white-space: nowrap +hr + margin-top: 20px + margin-bottom: 10px + +h2, h3, h4, h5, h6, ul, li + margin-bottom: 0 + +.container + width: 95% + max-width: 95% + +.grid + margin-bottom: 20px + width: 100% + height: 200px + .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) + +.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%) \ No newline at end of file