No more harp, some ES6

This commit is contained in:
Diego Rodríguez 2016-06-25 11:15:19 -05:00
parent 6570d9fc93
commit f61fb5ac71
No known key found for this signature in database
GPG key ID: E278B40A32DC6F7B
14 changed files with 672 additions and 23245 deletions

View file

@ -1,48 +0,0 @@
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 is the first fully-featured Browser WebTorrent Client")
meta(name="keywords" content="βTorrent, btorrent, client, webtorrent, browser, torrent, stream, bittorrent, torrenting, sharing, filesharing")
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.90,momentjs@2,angularjs@1.4(angular.min.js+angular-route.min.js+angular-sanitize.min.js),angular.ui-grid@3.1,angular.ng-notify@0.7,angular.file-upload@12")
link(rel="stylesheet" href="https://cdn.jsdelivr.net/g/normalize@3.0,skeleton@2.0,angular.ng-notify@0.7(ng-notify.min.css)")
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.1/ui-grid.min.css")
link(rel="stylesheet" href="style.css")
body(ng-controller="BTorrentCtrl" ng-cloak="")
header
h1
| βTorrent
span.version v{{$root.version}}
div.views(ng-show="$root.client.torrents.length == 0")
a(ng-href="/#") Full
| |
a(ng-href="/download") Single Download
| |
a(ng-href="/view") Stream / View
#viewer(ng-style="$root.viewerStyle")
#view(ng-view)
footer
a.button(href="https://github.com/DiegoRBaquero/BTorrent/issues" target="_blank")
i.fa.fa-github
| Suggest a feature / Report a bug
i.fa.fa-comment
br
b βTorrent is an Open-Source project by
a(href="https://diegorbaquero.com" target="_blank") DiegoRBaquero
br
b
a(href="https://tracker.btorrent.xyz/stats" target="_blank") βTorrent's Tracker Stats
br
| Powered by
a(href="https://github.com/feross/webtorrent" target="_blank") WebTorrent
br
small Hosted by
a(href="https://m.do.co/c/0b25a910e6e4" target="_blank") Digital Ocean
.spinner(ng-show="client.processing")
i.fa.fa-spinner.fa-spin.spinner-icon
script(src="app.js")

View file

@ -1,6 +1,6 @@
βTorrent
========
**[βTorrent]** is a fully-featured **[WebTorrent]** browser client written in [Jade], [CoffeeScript] and [Sass]
**[βTorrent]** is a fully-featured **[WebTorrent]** browser client written in HTML, JS and CSS
[![Join the chat at https://gitter.im/DiegoRBaquero/BTorrent](https://badges.gitter.im/DiegoRBaquero/BTorrent.svg)](https://gitter.im/DiegoRBaquero/BTorrent?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@ -33,18 +33,14 @@ Website powered by [jsDelivr] and [CloudFlare]. I use [nginx] in my server.
Don't like CloudFlare? No problem! Check [Direct-βTorrent].
### Easily built, tested and served
**I use [Harp] to rapidly test and compile the project**
### HTML5 serving
**You must serve index.html as the default**
Build the project into HTML, JS and CSS easily. Just use:
```bash
harp compile
For nginx, use this conf:
```
This will create a www folder with the compiled files
If you need to serve the files and view the compiled version instantly just use:
```bash
harp server
location / {
try_files $uri$args $uri$args/ /index.html;
}
```
### Enable Debugging

View file

@ -1,309 +0,0 @@
VERSION = "0.15"
BUILD = "2"
trackers = [
'wss://tracker.btorrent.xyz'
'wss://tracker.webtorrent.io'
'wss://tracker.openwebtorrent.com'
'wss://tracker.fastcast.nz'
]
opts = {
announce: trackers
}
rtcConfig = {
"iceServers": [
{
"url": "stun:23.21.150.121"
"urls": "stun:23.21.150.121"
}
]
}
debug = window.localStorage.getItem('debug')?
dbg = (string, item, color) ->
color = if color? then color else '#333333'
if debug
if item? && item.name
console.debug '%cβTorrent:' + (if item.infoHash? then 'torrent ' else 'torrent ' + item._torrent.name + ':file ') + item.name + (if item.infoHash? then ' (' + item.infoHash + ')' else '') + ' %c' + string, 'color: #33C3F0', 'color: ' + color
else
console.debug '%cβTorrent:client %c' + string, 'color: #33C3F0', 'color: ' + color
er = (err, item) ->
dbg err, item, '#FF0000'
dbg "Starting... v#{VERSION}b#{BUILD}"
client = new WebTorrent rtcConfig: rtcConfig
scope = null
app = angular.module 'BTorrent', ['ngRoute', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.selection', 'ngFileUpload', 'ngNotify'], ['$compileProvider','$locationProvider', '$routeProvider', ($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', ($scope, $rootScope, $http, $log, $location, ngNotify) ->
$rootScope.version = VERSION
ngNotify.config
duration: 5000
html: true
if !WebTorrent.WEBRTC_SUPPORT?
$rootScope.disabled = true
ngNotify.set 'Please use latest Chrome, Firefox or Opera', {type: 'error', sticky: true, button: false}
$rootScope.client = client
scope = $rootScope
updateAll = ->
if $rootScope.client.processing
return
$rootScope.$apply()
setInterval updateAll, 500
$rootScope.seedFiles = (files) ->
if files? && 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'
opts.name = name
$rootScope.client.processing = true
$rootScope.client.seed files, opts, $rootScope.onSeed
delete opts.name
$rootScope.openTorrentFile = (file) ->
if file?
dbg 'Adding torrent file ' + file.name
$rootScope.client.processing = true
$rootScope.client.add file, opts, $rootScope.onTorrent
$rootScope.client.on 'error', (err, torrent) ->
$rootScope.client.processing = false
ngNotify.set err, 'error'
er err, torrent
$rootScope.addMagnet = (magnet, onTorrent) ->
if magnet? && magnet.length > 0
dbg 'Adding magnet/hash ' + magnet
$rootScope.client.processing = true
$rootScope.client.add magnet, opts, onTorrent || $rootScope.onTorrent
$rootScope.destroyedTorrent = (err) ->
if err
throw err
dbg 'Destroyed torrent', $rootScope.selectedTorrent
$rootScope.selectedTorrent = null
$rootScope.client.processing = false
$rootScope.changePriority = (file) ->
if file.priority == '-1'
dbg 'Deselected', file
file.deselect()
else
dbg 'Selected with priority ' + file.priority, file
file.select(file.priority)
$rootScope.onTorrent = (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?)
$rootScope.selectedTorrent = torrent
$rootScope.client.processing = false
torrent.files.forEach (file) ->
file.getBlobURL (err, url) ->
if err
throw err
if isSeed
dbg 'Started seeding', torrent
if !($rootScope.selectedTorrent?)
$rootScope.selectedTorrent = torrent
$rootScope.client.processing = false
file.url = url
if !isSeed
dbg 'Done ', file
ngNotify.set '<b>' + file.name + '</b> ready for download', 'success'
torrent.on 'download', (chunkSize) ->
#if !isSeed
# dbg 'Downloaded chunk', torrent
torrent.on 'upload', (chunkSize) ->
#dbg 'Uploaded chunk', torrent
torrent.on 'done', ->
if !isSeed
dbg 'Done', torrent
ngNotify.set '<b>' + torrent.name + '</b> has finished downloading', 'success'
torrent.on 'wire', (wire, addr) ->
dbg 'Wire ' + addr, torrent
torrent.on 'error', (err) ->
er err
$rootScope.onSeed = (torrent) ->
$rootScope.onTorrent torrent, true
dbg "Ready"
]
app.controller 'FullCtrl', ['$scope','$rootScope','$http','$log','$location', 'ngNotify', ($scope, $rootScope, $http, $log, $location, ngNotify) ->
ngNotify.config
duration: 5000
html: true
$scope.addMagnet = ->
$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 = (gridApi) ->
$scope.gridApi = gridApi
gridApi.selection.on.rowSelectionChanged $scope, (row) ->
if !row.isSelected && $rootScope.selectedTorrent? && $rootScope.selectedTorrent.infoHash = row.entity.infoHash
$rootScope.selectedTorrent = null
else
$rootScope.selectedTorrent = row.entity
if $location.hash() != ''
$rootScope.client.processing = true
setTimeout ->
dbg 'Adding ' + $location.hash()
$rootScope.addMagnet $location.hash()
, 0
]
app.controller 'DownloadCtrl', ['$scope','$rootScope','$http','$log','$location', 'ngNotify', ($scope, $rootScope, $http, $log, $location, ngNotify) ->
ngNotify.config
duration: 5000
html: true
$scope.addMagnet = ->
$rootScope.addMagnet($scope.torrentInput)
$scope.torrentInput = ''
if $location.hash() != ''
$rootScope.client.processing = true
setTimeout ->
dbg 'Adding ' + $location.hash()
$rootScope.addMagnet $location.hash()
, 0
]
app.controller 'ViewCtrl', ['$scope','$rootScope','$http','$log','$location', 'ngNotify', ($scope, $rootScope, $http, $log, $location, ngNotify) ->
ngNotify.config
duration: 2000
html: true
onTorrent = (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 (file) ->
file.appendTo '#viewer'
file.getBlobURL (err, url) ->
if err
throw err
file.url = url
dbg 'Done ', file
torrent.on 'download', (chunkSize) ->
# dbg 'Downloaded chunk', torrent
torrent.on 'upload', (chunkSize) ->
#dbg 'Uploaded chunk', torrent
torrent.on 'done', ->
dbg 'Done', torrent
torrent.on 'wire', (wire, addr) ->
dbg 'Wire ' + addr, torrent
torrent.on 'error', (err) ->
er err
$scope.addMagnet = ->
$rootScope.addMagnet $scope.torrentInput, onTorrent
$scope.torrentInput = ''
if $location.hash() != ''
$rootScope.client.processing = true
setTimeout ->
dbg 'Adding ' + $location.hash()
$rootScope.addMagnet $location.hash(), onTorrent
, 0
]
app.filter 'html', ['$sce', ($sce) ->
(input) ->
$sce.trustAsHtml input
return
]
app.filter 'pbytes', ->
(num, speed) ->
if isNaN(num)
return ''
units = [
'B'
'kB'
'MB'
'GB'
'TB'
]
if num < 1
return (if speed then '' else '0 B')
exponent = Math.min(Math.floor(Math.log(num) / 6.907755278982137), 8)
num = (num / 1000 ** exponent).toFixed(1) * 1
unit = units[exponent]
num + ' ' + unit + (if speed then '/s' else '')
app.filter 'humanTime', ->
(millis) ->
if millis < 1000
return ''
remaining = moment.duration(millis).humanize()
remaining[0].toUpperCase() + remaining.substr(1)
app.filter 'progress', ->
(num) ->
(100 * num).toFixed(1) + '%'

376
app.js Normal file
View file

@ -0,0 +1,376 @@
let BUILD, VERSION, app, client, dbg, debug, er, opts, rtcConfig, trackers
VERSION = '0.15'
BUILD = '2'
trackers = ['wss://tracker.btorrent.xyz', 'wss://tracker.webtorrent.io', 'wss://tracker.openwebtorrent.com', 'wss://tracker.fastcast.nz']
opts = {
announce: trackers
}
rtcConfig = {
'iceServers': [
{
'url': 'stun:23.21.150.121',
'urls': 'stun:23.21.150.121'
}
]
}
debug = window.localStorage.getItem('debug') != null
dbg = function (string, item, color) {
color = color != null ? color : '#333333'
if (debug) {
if ((item != null) && 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}`)
}
}
}
er = function (err, item) { dbg(err, item, '#FF0000') }
dbg(`Starting... v${VERSION}b${BUILD}`)
client = new WebTorrent({
tracker: {
rtcConfig: rtcConfig,
announce: trackers
}
})
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
ngNotify.config({
duration: 5000,
html: true
})
if (WebTorrent.WEBRTC_SUPPORT == null) {
$rootScope.disabled = true
ngNotify.set('Please use latest Chrome, Firefox or Opera', {
type: 'error',
sticky: true,
button: false
})
}
$rootScope.client = client
scope = $rootScope
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'
opts.name = name
}
$rootScope.client.processing = true
$rootScope.client.seed(files, opts, $rootScope.onSeed)
delete opts.name
}
}
$rootScope.openTorrentFile = function (file) {
if (file != null) {
dbg(`Adding torrent file ${file.name}`)
$rootScope.client.processing = true
$rootScope.client.add(file, opts, $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, opts, 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(`<b>${file.name}</b> ready for download`, 'success')
}
})
})
torrent.on('done', function () {
if (!isSeed) {
dbg('Done', torrent)
}
ngNotify.set(`<b>${torrent.name}</b> 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', 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) { `${(100 * num).toFixed(1)}%` } })

34
index.html Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html ng-app="BTorrent" lang="en">
<head>
<base href="">
<meta charset="UTF-8">
<title>βTorrent: Browser WebTorrent Client</title>
<meta name="description" content="βTorrent is the first fully-featured Browser WebTorrent Client">
<meta name="keywords" content="βTorrent, btorrent, client, webtorrent, browser, torrent, stream, bittorrent, torrenting, sharing, filesharing">
<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,momentjs@2,angularjs@1.5(angular.min.js+angular-route.min.js+angular-sanitize.min.js),angular.ui-grid@3.1,angular.ng-notify@0.8,angular.file-upload@12"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/g/normalize@3.0,skeleton@2.0,angular.ng-notify@0.8(ng-notify.min.css)">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontawesome/4.6/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/angular.ui-grid/3.1/ui-grid.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body ng-controller="BTorrentCtrl" ng-cloak="">
<header>
<h1>βTorrent<span class="version"> v{{$root.version}}</span></h1>
<div class="views" ng-show="$root.client.torrents.length == 0"><a ng-href="/#">Full</a> | <a ng-href="/download">Single Download</a> | <a ng-href="/view">Stream / View</a></div>
</header>
<div id="viewer" ng-style="$root.viewerStyle"></div>
<div id="view" ng-view></div>
<footer>
<a class="button" href="https://github.com/DiegoRBaquero/BTorrent/issues" target="_blank"><i class="fa fa-github"></i> Suggest a feature / Report a bug <i class="fa fa-comment"></i></a><br>
<b>βTorrent is an Open-Source project by <a href="https://diegorbaquero.com" target="_blank">DiegoRBaquero</a></b><br>
<b> <a href="https://tracker.btorrent.xyz/stats" target="_blank">βTorrent's Tracker Stats</a></b><br>
Powered by <a href="https://github.com/feross/webtorrent" target="_blank">WebTorrent</a><br>
<small>Hosted by <a href="https://m.do.co/c/0b25a910e6e4" target="_blank">Digital Ocean</a></small>
</footer>
<div class="spinner" ng-show="client.processing"><i class="fa fa-spinner fa-spin spinner-icon"></i></div>
<script src="app.js"></script>
</body>
</html>

83
style.css Normal file
View file

@ -0,0 +1,83 @@
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; }

View file

@ -1,82 +0,0 @@
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

88
views/download.html Normal file
View file

@ -0,0 +1,88 @@
<div class="container">
<div ng-hide="$root.client.torrents.length != 0" style="vertical-align: middle; text-align: center">
<div class="row">
<form class="no-margin" ng-submit="addMagnet()">
<label>Enter magnet, hash or http(s) .torrent</label>
<input type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%"/>
</form>
<!--button(ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{"button-primary": torrentInput.length}")
i.fa.fa-download
| Download
-->
</div>
<div class="row">
<label>or...</label>
<button type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}"><i class="fa fa-folder-open"></i> Open torrent file</button>
</div>
</div>
<div class="div" ng-if="selectedTorrent" style="text-align: center">
<div class="four columns" style="overflow: auto">
<h4>Information</h4>
<table class="u-full-width">
<tbody>
<tr>
<td>Name</td>
<td>{{$root.selectedTorrent.name}}</td>
</tr>
<tr>
<td>Size</td>
<td>{{$root.selectedTorrent.length | pbytes}}</td>
</tr>
<tr>
<td>Completed</td>
<td>{{$root.selectedTorrent.progress | progress}} ({{$root.selectedTorrent.downloaded | pbytes}})</td>
</tr>
<tr>
<td>Peers</td>
<td>{{$root.selectedTorrent.numPeers}}</td>
</tr>
<tr>
<td>↓ Speed</td>
<td>{{$root.selectedTorrent.downloadSpeed | pbytes:1}}</td>
</tr>
<tr>
<td>ETA</td>
<td>{{$root.selectedTorrent.timeRemaining | humanTime}}</td>
</tr>
</tbody>
</table>
</div>
<div class="four columns">
<h4>Files</h4>
<table class="u-full-width" style="margin: auto">
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
<tr class="files" ng-repeat="file in $root.selectedTorrent.files">
<td ng-hide="file.done">{{file.name}}</td>
<td ng-show="file.done"><a ng-href="{{file.url}}" download="{{file.name}}" target="_self" ng-show="file.done">{{file.name}}</a></td>
<td>{{file.length | pbytes}}</td>
<td>
<select class="no-margin" name="{{file.name}}Priority" ng-model="file.priority" ng-init="file.priority = '0'" ng-change="$root.changePriority(file)">
<option value="1">High Priority</option>
<option value="0" selected="">Low Priority</option>
<option value="-1">Don't download</option>
</select>
</td>
</tr>
</tbody>
</table>
<h5>↑ Click a file to download it</h5>
</div>
<div class="four columns">
<h4>Share</h4>
<ul style="text-align: justify">
<li><a ng-href="#{{$root.selectedTorrent.infoHash}}" target="_blank">βTorrent</a></li>
<li><a ng-href="{{$root.selectedTorrent.magnetURI}}" target="_blank">Magnet URI</a></li>
<li><a ng-href="{{$root.selectedTorrent.safeTorrentFileURL}}" target="_self" download="{{$root.selectedTorrent.fileName}}">.torrent</a></li>
<li><strong>Hash: </strong>{{$root.selectedTorrent.infoHash}}</li>
</ul>
</div>
</div>
</div>

View file

@ -1,69 +0,0 @@
.container
div(ng-hide="$root.client.torrents.length != 0" style="vertical-align: middle; text-align: center")
.row
form.no-margin(ng-submit="addMagnet()")
label Enter magnet, hash or http(s) .torrent
input(type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%")
//button(ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{"button-primary": torrentInput.length}")
i.fa.fa-download
| Download
.row
label or...
button(type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}")
i.fa.fa-folder-open
| Open torrent file
.div(ng-if="selectedTorrent" style="text-align: center")
.four.columns(style="overflow: auto")
h4 Information
table.u-full-width
tbody
tr
td Name
td {{$root.selectedTorrent.name}}
tr
td Size
td {{$root.selectedTorrent.length | pbytes}}
tr
td Completed
td {{$root.selectedTorrent.progress | progress}} ({{$root.selectedTorrent.downloaded | pbytes}})
tr
td Peers
td {{$root.selectedTorrent.numPeers}}
tr
td ↓ Speed
td {{$root.selectedTorrent.downloadSpeed | pbytes:1}}
tr
td ETA
td {{$root.selectedTorrent.timeRemaining | humanTime}}
.four.columns
h4 Files
table.u-full-width(style="margin: auto")
thead
tr
th Name
th Size
th Priority
tbody
tr.files(ng-repeat="file in $root.selectedTorrent.files")
td(ng-hide="file.done") {{file.name}}
td(ng-show="file.done")
a(ng-href="{{file.url}}" download="{{file.name}}" target="_self" ng-show="file.done") {{file.name}}
td {{file.length | pbytes}}
td
select.no-margin(name="{{file.name}}Priority" ng-model="file.priority" ng-init="file.priority = '0'" ng-change="$root.changePriority(file)")
option(value="1") High Priority
option(value="0" selected="") Low Priority
option(value="-1") Don't download
h5 ↑ Click a file to download it
.four.columns
h4 Share
ul(style="text-align: justify")
li
a(ng-href="#{{$root.selectedTorrent.infoHash}}" target="_blank") βTorrent
li
a(ng-href="{{$root.selectedTorrent.magnetURI}}" target="_blank") Magnet URI
li
a(ng-href="{{$root.selectedTorrent.safeTorrentFileURL}}" target="_self" download="{{$root.selectedTorrent.fileName}}") .torrent
li
strong Hash:
| {{$root.selectedTorrent.infoHash}}

64
views/full.html Normal file
View file

@ -0,0 +1,64 @@
<div class="container">
<div class="row">
<div class="four columns">
<input class="u-full-width" type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled"/>
</div>
<div class="two columns download-button">
<button ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{'button-primary': torrentInput.length}"><i class="fa fa-download"></i> Download</button>
</div>
<div class="three columns">
<button type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}"><i class="fa fa-folder-open"></i> Open torrent file</button>
</div>
<div class="three columns u-pull-right">
<button class="u-pull-right" ngf-select="$root.seedFiles($files)" multiple="" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}"><i class="fa fa-upload"></i> Seed files</button>
</div>
</div>
<div class="row grid" ui-grid="gridOptions" ui-grid-resize-columns="ui-grid-resize-columns" ui-grid-selection="ui-grid-selection"></div>
<div class="row" ng-if="selectedTorrent">
<div class="six columns" style="overflow: auto">
<h5>{{$root.selectedTorrent.name}}
<button ng-if="!$root.selectedTorrent.swarm.paused" ng-click="$root.selectedTorrent.pause()"><i class="fa fa-pause"></i> Pause</button>
<button ng-if="$root.selectedTorrent.swarm.paused" ng-click="$root.selectedTorrent.resume()"><i class="fa fa-play"></i> Resume</button>
<button class="button-danger" ng-click="$root.selectedTorrent.destroy($root.destroyedTorrent)"><i class="fa fa-times"></i> Remove</button>
</h5>
<h6>Share</h6>
<ul>
<li><a ng-href="#{{$root.selectedTorrent.infoHash}}" target="_blank">βTorrent</a></li>
<li><a ng-href="{{$root.selectedTorrent.magnetURI}}" target="_blank">Magnet URI</a></li>
<li><a ng-href="{{$root.selectedTorrent.safeTorrentFileURL}}" target="_self" download="{{$root.selectedTorrent.fileName}}">.torrent</a></li>
<li><strong>Hash: </strong>{{$root.selectedTorrent.infoHash}} </li>
</ul>
</div>
<div class="six columns">
<h5>Files</h5>
<table class="u-full-width">
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
<tr class="files" ng-repeat="file in $root.selectedTorrent.files">
<td ng-hide="file.done">{{file.name}}</td>
<td ng-show="file.done"><a ng-href="{{file.url}}" download="{{file.name}}" target="_self" ng-show="file.done">{{file.name}}</a></td>
<td>{{file.length | pbytes}}</td>
<td>
<select class="no-margin" name="{{file.name}}Priority" ng-model="file.priority" ng-init="file.priority = '0'" ng-change="$root.changePriority(file)">
<option value="1">High Priority</option>
<option value="0" selected="">Low Priority</option>
<option value="-1">Don't download</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="center"><strong>Client Stats:
↓ {{$root.client.downloadSpeed | pbytes}}/s ·
↑ {{$root.client.uploadSpeed | pbytes}}/s ·
Ratio: {{$root.client.ratio | number:2}}</strong></div>
</div>

View file

@ -1,66 +0,0 @@
.container
.row
.four.columns
input.u-full-width(type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled")
.two.columns.download-button
button(ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{'button-primary': torrentInput.length}")
i.fa.fa-download
| Download
.three.columns
button(type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}")
i.fa.fa-folder-open
| Open torrent file
.three.columns.u-pull-right
button.u-pull-right(ngf-select="$root.seedFiles($files)" multiple="" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}")
i.fa.fa-upload
| Seed files
.row.grid(ui-grid="gridOptions" ui-grid-resize-columns, ui-grid-selection)
.row(ng-if="selectedTorrent")
.six.columns(style="overflow: auto")
h5 {{$root.selectedTorrent.name}}
button(ng-if="!$root.selectedTorrent.swarm.paused" ng-click="$root.selectedTorrent.pause()")
i.fa.fa-pause
| Pause
|
button(ng-if="$root.selectedTorrent.swarm.paused" ng-click="$root.selectedTorrent.resume()")
i.fa.fa-play
| Resume
|
button.button-danger(ng-click="$root.selectedTorrent.destroy($root.destroyedTorrent)")
i.fa.fa-times
| Remove
h6 Share
ul
li
a(ng-href="#{{$root.selectedTorrent.infoHash}}" target="_blank") βTorrent
li
a(ng-href="{{$root.selectedTorrent.magnetURI}}" target="_blank") Magnet URI
li
a(ng-href="{{$root.selectedTorrent.safeTorrentFileURL}}" target="_self" download="{{$root.selectedTorrent.fileName}}") .torrent
li
strong Hash:
| {{$root.selectedTorrent.infoHash}}
.six.columns
h5 Files
table.u-full-width
thead
tr
th Name
th Size
th Priority
tbody
tr.files(ng-repeat="file in $root.selectedTorrent.files")
td(ng-hide="file.done") {{file.name}}
td(ng-show="file.done")
a(ng-href="{{file.url}}" download="{{file.name}}" target="_self" ng-show="file.done") {{file.name}}
td {{file.length | pbytes}}
td
select.no-margin(name="{{file.name}}Priority" ng-model="file.priority" ng-init="file.priority = '0'" ng-change="$root.changePriority(file)")
option(value="1") High Priority
option(value="0" selected="") Low Priority
option(value="-1") Don't download
.center
strong Client Stats:
| ↓ {{$root.client.downloadSpeed | pbytes}}/s ·
| ↑ {{$root.client.uploadSpeed | pbytes}}/s ·
| Ratio: {{$root.client.ratio | number:2}}

20
views/view.html Normal file
View file

@ -0,0 +1,20 @@
<div class="container">
<div ng-hide="$root.client.torrents.length != 0" style="vertical-align: middle; text-align: center">
<div class="row">
<form class="no-margin" ng-submit="addMagnet()">
<label>Enter magnet, hash or http(s) .torrent</label>
<input type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%"/>
</form>
<!--button(ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{"button-primary": torrentInput.length}")
i.fa.fa-download
| Download
-->
</div>
<div class="row">
<label>or...</label>
<button type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}"><i class="fa fa-folder-open"></i> Open torrent file</button>
</div>
</div>
<div class="div" ng-if="selectedTorrent" style="text-align: center">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}}</div>
</div>

View file

@ -1,16 +0,0 @@
.container
div(ng-hide="$root.client.torrents.length != 0" style="vertical-align: middle; text-align: center")
.row
form.no-margin(ng-submit="addMagnet()")
label Enter magnet, hash or http(s) .torrent
input(type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%")
//button(ng-click="addMagnet()" ng-disabled="!torrentInput.length || $root.disabled" ng-class="{"button-primary": torrentInput.length}")
i.fa.fa-download
| Download
.row
label or...
button(type="file" ngf-select="$root.openTorrentFile($file)" ng-disabled="$root.disabled" ng-class="{'button-primary': !$root.disabled}")
i.fa.fa-folder-open
| Open torrent file
.div(ng-if="selectedTorrent" style="text-align: center")
| 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}}

File diff suppressed because it is too large Load diff