whisper.cat stuff
This commit is contained in:
372
weboasis/torrent/app.js
Normal file
372
weboasis/torrent/app.js
Normal file
@ -0,0 +1,372 @@
|
||||
const VERSION = '1.0'
|
||||
|
||||
const trackers = ['wss://tracker.sloppyta.co:443/announce', 'wss://tracker.openwebtorrent.com', 'wss://tracker.novage.com.ua:443/announce', 'wss://tracker.btorrent.xyz', 'wss://tracker.webtorrent.io']
|
||||
|
||||
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}`)
|
||||
|
||||
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
|
||||
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
|
||||
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(`<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', 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)}%` } })
|
4
weboasis/torrent/css/font-awesome.min.css
vendored
Normal file
4
weboasis/torrent/css/font-awesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
849
weboasis/torrent/css/libraries.min.css
vendored
Normal file
849
weboasis/torrent/css/libraries.min.css
vendored
Normal file
@ -0,0 +1,849 @@
|
||||
|
||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS and IE text size adjust after device orientation change,
|
||||
* without disabling user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||
* and Firefox.
|
||||
* Correct `block` display not defined for `main` in IE 11.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability of focused elements when they are also in an
|
||||
* active/hover state.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9/10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow not hidden in IE 9/10/11.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contain overflow in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address odd `em`-unit font size rendering in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||
* styling of `select`, unless a `border` property is set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. Correct color not being inherited.
|
||||
* Known issue: affects color of disabled elements.
|
||||
* 2. Correct font properties not being inherited.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||
* Correct `select` style inheritance in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's recommended that you don't attempt to style these elements.
|
||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
||||
*
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||
* `font-size` values of the `input`, it causes the cursor style of the
|
||||
* decrement button to change from `default` to `text`.
|
||||
*/
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
box-sizing: content-box; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||
* padding (and `textfield` appearance).
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skeleton V2.0.4
|
||||
* Copyright 2014, Dave Gamache
|
||||
* www.getskeleton.com
|
||||
* Free to use under the MIT license.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* 12/29/2014
|
||||
*/
|
||||
|
||||
|
||||
/* Table of contents
|
||||
––––––––––––––––––––––––––––––––––––––––––––––––––
|
||||
- Grid
|
||||
- Base Styles
|
||||
- Typography
|
||||
- Links
|
||||
- Buttons
|
||||
- Forms
|
||||
- Lists
|
||||
- Code
|
||||
- Tables
|
||||
- Spacing
|
||||
- Utilities
|
||||
- Clearing
|
||||
- Media Queries
|
||||
*/
|
||||
|
||||
|
||||
/* Grid
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box; }
|
||||
.column,
|
||||
.columns {
|
||||
width: 100%;
|
||||
float: left;
|
||||
box-sizing: border-box; }
|
||||
|
||||
/* For devices larger than 400px */
|
||||
@media (min-width: 400px) {
|
||||
.container {
|
||||
width: 85%;
|
||||
padding: 0; }
|
||||
}
|
||||
|
||||
/* For devices larger than 550px */
|
||||
@media (min-width: 550px) {
|
||||
.container {
|
||||
width: 80%; }
|
||||
.column,
|
||||
.columns {
|
||||
margin-left: 4%; }
|
||||
.column:first-child,
|
||||
.columns:first-child {
|
||||
margin-left: 0; }
|
||||
|
||||
.one.column,
|
||||
.one.columns { width: 4.66666666667%; }
|
||||
.two.columns { width: 13.3333333333%; }
|
||||
.three.columns { width: 22%; }
|
||||
.four.columns { width: 30.6666666667%; }
|
||||
.five.columns { width: 39.3333333333%; }
|
||||
.six.columns { width: 48%; }
|
||||
.seven.columns { width: 56.6666666667%; }
|
||||
.eight.columns { width: 65.3333333333%; }
|
||||
.nine.columns { width: 74.0%; }
|
||||
.ten.columns { width: 82.6666666667%; }
|
||||
.eleven.columns { width: 91.3333333333%; }
|
||||
.twelve.columns { width: 100%; margin-left: 0; }
|
||||
|
||||
.one-third.column { width: 30.6666666667%; }
|
||||
.two-thirds.column { width: 65.3333333333%; }
|
||||
|
||||
.one-half.column { width: 48%; }
|
||||
|
||||
/* Offsets */
|
||||
.offset-by-one.column,
|
||||
.offset-by-one.columns { margin-left: 8.66666666667%; }
|
||||
.offset-by-two.column,
|
||||
.offset-by-two.columns { margin-left: 17.3333333333%; }
|
||||
.offset-by-three.column,
|
||||
.offset-by-three.columns { margin-left: 26%; }
|
||||
.offset-by-four.column,
|
||||
.offset-by-four.columns { margin-left: 34.6666666667%; }
|
||||
.offset-by-five.column,
|
||||
.offset-by-five.columns { margin-left: 43.3333333333%; }
|
||||
.offset-by-six.column,
|
||||
.offset-by-six.columns { margin-left: 52%; }
|
||||
.offset-by-seven.column,
|
||||
.offset-by-seven.columns { margin-left: 60.6666666667%; }
|
||||
.offset-by-eight.column,
|
||||
.offset-by-eight.columns { margin-left: 69.3333333333%; }
|
||||
.offset-by-nine.column,
|
||||
.offset-by-nine.columns { margin-left: 78.0%; }
|
||||
.offset-by-ten.column,
|
||||
.offset-by-ten.columns { margin-left: 86.6666666667%; }
|
||||
.offset-by-eleven.column,
|
||||
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
|
||||
|
||||
.offset-by-one-third.column,
|
||||
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
|
||||
.offset-by-two-thirds.column,
|
||||
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
|
||||
|
||||
.offset-by-one-half.column,
|
||||
.offset-by-one-half.columns { margin-left: 52%; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Base Styles
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
/* NOTE
|
||||
html is set to 62.5% so that all the REM measurements throughout Skeleton
|
||||
are based on 10px sizing. So basically 1.5rem = 15px :) */
|
||||
html {
|
||||
font-size: 62.5%; }
|
||||
body {
|
||||
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
|
||||
line-height: 1.6;
|
||||
font-weight: 400;
|
||||
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #222; }
|
||||
|
||||
|
||||
/* Typography
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: 300; }
|
||||
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
|
||||
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
|
||||
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
|
||||
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
|
||||
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
|
||||
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
|
||||
|
||||
/* Larger than phablet */
|
||||
@media (min-width: 550px) {
|
||||
h1 { font-size: 5.0rem; }
|
||||
h2 { font-size: 4.2rem; }
|
||||
h3 { font-size: 3.6rem; }
|
||||
h4 { font-size: 3.0rem; }
|
||||
h5 { font-size: 2.4rem; }
|
||||
h6 { font-size: 1.5rem; }
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0; }
|
||||
|
||||
|
||||
/* Links
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
a {
|
||||
color: #1EAEDB; }
|
||||
a:hover {
|
||||
color: #0FA0CE; }
|
||||
|
||||
|
||||
/* Buttons
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.button,
|
||||
button,
|
||||
input[type="submit"],
|
||||
input[type="reset"],
|
||||
input[type="button"] {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
padding: 0 30px;
|
||||
color: #555;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 38px;
|
||||
letter-spacing: .1rem;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #bbb;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box; }
|
||||
.button:hover,
|
||||
button:hover,
|
||||
input[type="submit"]:hover,
|
||||
input[type="reset"]:hover,
|
||||
input[type="button"]:hover,
|
||||
.button:focus,
|
||||
button:focus,
|
||||
input[type="submit"]:focus,
|
||||
input[type="reset"]:focus,
|
||||
input[type="button"]:focus {
|
||||
color: #333;
|
||||
border-color: #888;
|
||||
outline: 0; }
|
||||
.button.button-primary,
|
||||
button.button-primary,
|
||||
input[type="submit"].button-primary,
|
||||
input[type="reset"].button-primary,
|
||||
input[type="button"].button-primary {
|
||||
color: #FFF;
|
||||
background-color: #33C3F0;
|
||||
border-color: #33C3F0; }
|
||||
.button.button-primary:hover,
|
||||
button.button-primary:hover,
|
||||
input[type="submit"].button-primary:hover,
|
||||
input[type="reset"].button-primary:hover,
|
||||
input[type="button"].button-primary:hover,
|
||||
.button.button-primary:focus,
|
||||
button.button-primary:focus,
|
||||
input[type="submit"].button-primary:focus,
|
||||
input[type="reset"].button-primary:focus,
|
||||
input[type="button"].button-primary:focus {
|
||||
color: #FFF;
|
||||
background-color: #1EAEDB;
|
||||
border-color: #1EAEDB; }
|
||||
|
||||
|
||||
/* Forms
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="search"],
|
||||
input[type="text"],
|
||||
input[type="tel"],
|
||||
input[type="url"],
|
||||
input[type="password"],
|
||||
textarea,
|
||||
select {
|
||||
height: 38px;
|
||||
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
|
||||
background-color: #fff;
|
||||
border: 1px solid #D1D1D1;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box; }
|
||||
/* Removes awkward default styles on some inputs for iOS */
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="search"],
|
||||
input[type="text"],
|
||||
input[type="tel"],
|
||||
input[type="url"],
|
||||
input[type="password"],
|
||||
textarea {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none; }
|
||||
textarea {
|
||||
min-height: 65px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px; }
|
||||
input[type="email"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border: 1px solid #33C3F0;
|
||||
outline: 0; }
|
||||
label,
|
||||
legend {
|
||||
display: block;
|
||||
margin-bottom: .5rem;
|
||||
font-weight: 600; }
|
||||
fieldset {
|
||||
padding: 0;
|
||||
border-width: 0; }
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
display: inline; }
|
||||
label > .label-body {
|
||||
display: inline-block;
|
||||
margin-left: .5rem;
|
||||
font-weight: normal; }
|
||||
|
||||
|
||||
/* Lists
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
ul {
|
||||
list-style: circle inside; }
|
||||
ol {
|
||||
list-style: decimal inside; }
|
||||
ol, ul {
|
||||
padding-left: 0;
|
||||
margin-top: 0; }
|
||||
ul ul,
|
||||
ul ol,
|
||||
ol ol,
|
||||
ol ul {
|
||||
margin: 1.5rem 0 1.5rem 3rem;
|
||||
font-size: 90%; }
|
||||
li {
|
||||
margin-bottom: 1rem; }
|
||||
|
||||
|
||||
/* Code
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
code {
|
||||
padding: .2rem .5rem;
|
||||
margin: 0 .2rem;
|
||||
font-size: 90%;
|
||||
white-space: nowrap;
|
||||
background: #F1F1F1;
|
||||
border: 1px solid #E1E1E1;
|
||||
border-radius: 4px; }
|
||||
pre > code {
|
||||
display: block;
|
||||
padding: 1rem 1.5rem;
|
||||
white-space: pre; }
|
||||
|
||||
|
||||
/* Tables
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
th,
|
||||
td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #E1E1E1; }
|
||||
th:first-child,
|
||||
td:first-child {
|
||||
padding-left: 0; }
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
padding-right: 0; }
|
||||
|
||||
|
||||
/* Spacing
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
button,
|
||||
.button {
|
||||
margin-bottom: 1rem; }
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
fieldset {
|
||||
margin-bottom: 1.5rem; }
|
||||
pre,
|
||||
blockquote,
|
||||
dl,
|
||||
figure,
|
||||
table,
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
form {
|
||||
margin-bottom: 2.5rem; }
|
||||
|
||||
|
||||
/* Utilities
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.u-full-width {
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.u-max-full-width {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.u-pull-right {
|
||||
float: right; }
|
||||
.u-pull-left {
|
||||
float: left; }
|
||||
|
||||
|
||||
/* Misc
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
hr {
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 3.5rem;
|
||||
border-width: 0;
|
||||
border-top: 1px solid #E1E1E1; }
|
||||
|
||||
|
||||
/* Clearing
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
|
||||
/* Self Clearing Goodness */
|
||||
.container:after,
|
||||
.row:after,
|
||||
.u-cf {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both; }
|
||||
|
||||
|
||||
/* Media Queries
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
/*
|
||||
Note: The best way to structure the use of media queries is to create the queries
|
||||
near the relevant code. For example, if you wanted to change the styles for buttons
|
||||
on small devices, paste the mobile query code up in the buttons section and style it
|
||||
there.
|
||||
*/
|
||||
|
||||
|
||||
/* Larger than mobile */
|
||||
@media (min-width: 400px) {}
|
||||
|
||||
/* Larger than phablet (also point when grid becomes active) */
|
||||
@media (min-width: 550px) {}
|
||||
|
||||
/* Larger than tablet */
|
||||
@media (min-width: 750px) {}
|
||||
|
||||
/* Larger than desktop */
|
||||
@media (min-width: 1000px) {}
|
||||
|
||||
/* Larger than Desktop HD */
|
||||
@media (min-width: 1200px) {}
|
||||
|
||||
|
||||
.ngn{color:#FFF;cursor:default;display:none;font-size:1.3em;left:0;opacity:1;padding:25px 80px;position:fixed;right:0;text-align:center;user-select:none;z-index:9999;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.ngn-component{position:absolute}.ngn-top{top:0}.ngn-bottom{bottom:0}.ngn-dismiss{background-color:#333;border-radius:15px;box-shadow:inset 2px 2px 7px 2px #000;color:#DDD;cursor:pointer;display:none;font-size:1.25em;font-weight:700;height:30px;line-height:30px;opacity:.2;position:absolute;right:40px;text-shadow:1px 1px 5px #000;top:25px;width:30px}.ngn-sticky .ngn-dismiss{display:block}.ngn-dismiss:hover{background-color:#000}.ngn-dismiss:active{background-color:#666}@media only screen and (max-width:480px){.ngn{font-size:1em;padding:12px 25px}.ngn-dismiss{font-size:1em;height:20px;line-height:20px;right:5px;top:5px;width:20px}}.ngn-info{background-color:#0e90d2}.ngn-error{background-color:#dd514c}.ngn-success{background-color:#5eb95e}.ngn-warn{background-color:#f37b1d}.ngn-grimace{background-color:#8058a5}.ngn-prime.ngn-info{background-color:#03c}.ngn-prime.ngn-error{background-color:red}.ngn-prime.ngn-success{background-color:#0c0}.ngn-prime.ngn-warn{background-color:#f90}.ngn-prime.ngn-grimace{background-color:#609}.ngn-pastel.ngn-info{background-color:#7EA7D8}.ngn-pastel.ngn-error{background-color:#F6989D}.ngn-pastel.ngn-success{background-color:#82CA9D}.ngn-pastel.ngn-warn{background-color:#FDC68A}.ngn-pastel.ngn-grimace{background-color:#A187BE}.ngn-pitchy.ngn-info{background-color:#003471}.ngn-pitchy.ngn-error{background-color:#9E0B0F}.ngn-pitchy.ngn-success{background-color:#007236}.ngn-pitchy.ngn-warn{background-color:#A36209}.ngn-pitchy.ngn-grimace{background-color:#440E62}
|
||||
|
1
weboasis/torrent/css/style.min.css
vendored
Normal file
1
weboasis/torrent/css/style.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
body{height:100%;width:100%}.center,footer,header{text-align:center}td,th{padding:2px 15px;max-width:200px;overflow:auto;white-space:nowrap}h2,h3,h4,h5,h6,li,ul{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:.3em}.views{margin-top:-20px;margin-bottom:10px}.download-button{margin-left:10px}.no-margin{margin:0}.spinner{position:absolute;top:30%;left:30%;width:40%;height:40%;z-index:1000;background-color:gray;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=button].button-danger,input[type=reset].button-danger,input[type=submit].button-danger{color:#fff;background-color:#d9534f;border-color:#d9534f}.button.button-danger:focus,.button.button-danger:hover,button.button-danger:focus,button.button-danger:hover,input[type=button].button-danger:focus,input[type=button].button-danger:hover,input[type=reset].button-danger:focus,input[type=reset].button-danger:hover,input[type=submit].button-danger:focus,input[type=submit].button-danger:hover{color:#fff;background-color:#c43e3a;border-color:#c43e3a}a{text-decoration:none}
|
4
weboasis/torrent/css/ui-grid.min.css
vendored
Normal file
4
weboasis/torrent/css/ui-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
weboasis/torrent/favicon.ico
Normal file
BIN
weboasis/torrent/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
weboasis/torrent/fonts/FontAwesome.otf
Normal file
BIN
weboasis/torrent/fonts/FontAwesome.otf
Normal file
Binary file not shown.
BIN
weboasis/torrent/fonts/fontawesome-webfont.eot
Normal file
BIN
weboasis/torrent/fonts/fontawesome-webfont.eot
Normal file
Binary file not shown.
2671
weboasis/torrent/fonts/fontawesome-webfont.svg
Normal file
2671
weboasis/torrent/fonts/fontawesome-webfont.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
BIN
weboasis/torrent/fonts/fontawesome-webfont.ttf
Normal file
BIN
weboasis/torrent/fonts/fontawesome-webfont.ttf
Normal file
Binary file not shown.
BIN
weboasis/torrent/fonts/fontawesome-webfont.woff
Normal file
BIN
weboasis/torrent/fonts/fontawesome-webfont.woff
Normal file
Binary file not shown.
BIN
weboasis/torrent/fonts/fontawesome-webfont.woff2
Normal file
BIN
weboasis/torrent/fonts/fontawesome-webfont.woff2
Normal file
Binary file not shown.
37
weboasis/torrent/index.html
Normal file
37
weboasis/torrent/index.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="BTorrent" lang="en">
|
||||
<head>
|
||||
<base href="https://weboasis.whisper.cat/torrent/" />
|
||||
<meta charset="UTF-8" />
|
||||
<title>WebOasis - WebTorrent Client</title>
|
||||
<meta name="description" content="Browser Torrent Client" />
|
||||
<meta name="keywords" content="client, webtorrent, browser, torrent, stream, bittorrent, torrenting, sharing, filesharing, stream, streaming, stream torrents" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script src="libraries.min.js"></script>
|
||||
<link rel="stylesheet" href="css/libraries.min.css" />
|
||||
<link rel="stylesheet" href="css/font-awesome.min.css" />
|
||||
<link rel="stylesheet" href="css/ui-grid.min.css" />
|
||||
<link rel="stylesheet" href="css/style.min.css" />
|
||||
</head>
|
||||
<body ng-controller="BTorrentCtrl" ng-cloak="">
|
||||
<header>
|
||||
<h1>WebTorrent Client</h1>
|
||||
<div class="views" ng-show="$root.client.torrents.length == 0">
|
||||
<a ng-href="/torrent/#">Full</a> | <a ng-href="/torrent/download">Single Download</a> |
|
||||
<a ng-href="/torrent/view">Stream / View</a>
|
||||
</div>
|
||||
<div class="aligncenter" style="width: 468px; display: inline-block;"></div>
|
||||
</header>
|
||||
<div id="viewer" ng-style="$root.viewerStyle"></div>
|
||||
<div id="view" ng-view></div>
|
||||
<footer>
|
||||
<a class="button" href="https://weboasis.whisper.cat/torrent/make" target="_blank">Create A Torrent File</a><br />
|
||||
<a class="button" href="https://weboasis.whisper.cat/torrent/t2m" target="_blank">Convert Torrent to Magnet</a><br />
|
||||
<a class="button" href="https://yutzuko-torrent.appspot.com" target="_blank">Batch Torrent Editor</a><br />
|
||||
<a class="button" href="https://webtor.io" target="_blank">WebTor.io</a><br />
|
||||
<a class="button" href="https://weboasis.whisper.cat">Back to WebOasis.whisper.cat</a>
|
||||
</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>
|
405
weboasis/torrent/libraries.min.js
vendored
Normal file
405
weboasis/torrent/libraries.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
weboasis/torrent/make/favicon.png
Normal file
BIN
weboasis/torrent/make/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1005 B |
1413
weboasis/torrent/make/index.html
Normal file
1413
weboasis/torrent/make/index.html
Normal file
File diff suppressed because one or more lines are too long
BIN
weboasis/torrent/t2m/favicon.png
Normal file
BIN
weboasis/torrent/t2m/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 B |
56
weboasis/torrent/t2m/index.html
Normal file
56
weboasis/torrent/t2m/index.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content="Convert torrent files to magnet URIs using Javascript" />
|
||||
<meta name="keywords" content="torrent,magnet,javascript,convert,online,sha1,bencode,base32" />
|
||||
<title>WebOas.is - Torrent to Magnet Converter</title>
|
||||
<link rel="shortcut icon" href="favicon.png" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<script src="src/t2m.loader.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header_bar">
|
||||
<div class="main main_no_overflow header">
|
||||
<table class="header_table"><tbody>
|
||||
<tr>
|
||||
<td class="header_table_cell header_table_cell_full">
|
||||
<div class="header_table_description">
|
||||
<div class="header_table_description_name"><h3>Torrent to Magnet</h3></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main body">
|
||||
<p><div class="script_disabled script_visible">Javascript is required to use the inline converter.</div>
|
||||
<div class="script_enabled">
|
||||
<div class="converter">
|
||||
<div class="converter_container">
|
||||
<div class="converter_table">
|
||||
|
||||
<div class="converter_cell converter_cell_left">
|
||||
<div class="converter_svg_container">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" class="converter_svg_graphic">
|
||||
<polygon points="0.7,0 0.7,0.5 1,0.5 0.5,1 0,0.5 0.3,0.5 0.3,0" class="converter_svg_graphic_poly"></polygon>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="converter_cell converter_cell_right">
|
||||
<div class="converter_info">
|
||||
<div class="converter_info_line1">Drop <a class="link_external light_underline link_stop_propagation" href="https://en.wikipedia.org/wiki/Torrent_file" target="_blank"><span>.torrent</span></a> files here</div>
|
||||
<div class="converter_info_line2">to convert them to <a class="link_external light_underline link_stop_propagation" href="https://en.wikipedia.org/wiki/Magnet_uri" target="_blank"><span>magnet URI</span></a>s</div>
|
||||
<div class="converter_info_line3">Or click to open the file browser</div>
|
||||
<input type="file" class="converter_files_input" multiple />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div></p>
|
||||
<div class="converted"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
103
weboasis/torrent/t2m/src/base32.js
Normal file
103
weboasis/torrent/t2m/src/base32.js
Normal file
@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
|
||||
// Module for encoding/decoding base32
|
||||
var Base32 = (function () {
|
||||
"use strict";
|
||||
|
||||
// Vars used
|
||||
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
||||
pad_lengths = [ 0, 1, 3, 4, 6 ],
|
||||
pad_char = "=";
|
||||
|
||||
|
||||
|
||||
// Encode/decode functions
|
||||
return {
|
||||
/**
|
||||
Encode a string into base32
|
||||
|
||||
@param str
|
||||
The string to convert.
|
||||
This string should be encoded in some way such that each character is in the range [0,255]
|
||||
@return
|
||||
A base32 encoded string
|
||||
*/
|
||||
encode: function (str) {
|
||||
var len = str.length,
|
||||
str_new = "",
|
||||
i = 0,
|
||||
c1, c2, c3, c4, c5;
|
||||
|
||||
// Null pad
|
||||
while ((str.length % 5) !== 0) str += "\x00";
|
||||
|
||||
// String modify
|
||||
while (i < len) {
|
||||
c1 = str.charCodeAt(i++);
|
||||
c2 = str.charCodeAt(i++);
|
||||
c3 = str.charCodeAt(i++);
|
||||
c4 = str.charCodeAt(i++);
|
||||
c5 = str.charCodeAt(i++);
|
||||
|
||||
str_new += alphabet[(c1 >> 3)];
|
||||
str_new += alphabet[((c1 & 0x07) << 2) | (c2 >> 6)];
|
||||
str_new += alphabet[((c2 & 0x3F) >> 1)];
|
||||
str_new += alphabet[((c2 & 0x01) << 4) | (c3 >> 4)];
|
||||
str_new += alphabet[((c3 & 0x0F) << 1) | (c4 >> 7)];
|
||||
str_new += alphabet[((c4 & 0x7F) >> 2)];
|
||||
str_new += alphabet[((c4 & 0x03) << 3) | (c5 >> 5)];
|
||||
str_new += alphabet[(c5 & 0x1F)];
|
||||
}
|
||||
|
||||
// Padding
|
||||
if (i > len) {
|
||||
i = pad_lengths[i - len]; // (i - len) equals the number of times \x00 was padded
|
||||
str_new = str_new.substr(0, str_new.length - i);
|
||||
while ((str_new.length % 8) !== 0) str_new += pad_char;
|
||||
}
|
||||
|
||||
// Done
|
||||
return str_new;
|
||||
},
|
||||
/**
|
||||
Decode a string from base32
|
||||
|
||||
@param str
|
||||
A valid base32 string
|
||||
@return
|
||||
The original string
|
||||
*/
|
||||
decode: function (str) {
|
||||
var len = str.length,
|
||||
str_new = "",
|
||||
bits = 0,
|
||||
char_buffer = 0,
|
||||
i;
|
||||
|
||||
// Cut off padding
|
||||
while (len > 0 && str[len - 1] == "=") --len;
|
||||
|
||||
// Iterate
|
||||
for (i = 0; i < len; ++i) {
|
||||
// Update with the 32bit value
|
||||
char_buffer = (char_buffer << 5) | alphabet.indexOf(str[i]);
|
||||
|
||||
// Update bitcount
|
||||
bits += 5;
|
||||
if (bits >= 8) {
|
||||
// Update string
|
||||
str_new += String.fromCharCode((char_buffer >> (bits - 8)) & 0xFF);
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
return str_new;
|
||||
},
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
202
weboasis/torrent/t2m/src/bencode.js
Normal file
202
weboasis/torrent/t2m/src/bencode.js
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
|
||||
|
||||
// Module for encoding/decoding Bencoded data
|
||||
var Bencode = (function () {
|
||||
"use strict";
|
||||
|
||||
// Encoding functions
|
||||
var encode = function (value) {
|
||||
// Type
|
||||
var t = typeof(value);
|
||||
|
||||
// Number
|
||||
if (t == "number") return encode_int(Math.floor(value));
|
||||
// String
|
||||
if (t == "string") return encode_string(value);
|
||||
// Array
|
||||
if (Array.isArray(value)) return encode_list(value);
|
||||
// Dict
|
||||
return encode_dict(value);
|
||||
};
|
||||
|
||||
var encode_int = function (value) {
|
||||
return "i" + value + "e";
|
||||
};
|
||||
var encode_string = function (value) {
|
||||
return "" + value.length + ":" + value;
|
||||
};
|
||||
var encode_list = function (value) {
|
||||
var str = [ "l" ],
|
||||
i;
|
||||
|
||||
// List values
|
||||
for (i = 0; i < value.length; ++i) {
|
||||
str.push(encode(value[i]));
|
||||
}
|
||||
|
||||
// End
|
||||
str.push("e");
|
||||
return str.join("");
|
||||
};
|
||||
var encode_dict = function (value) {
|
||||
var str = [ "d" ],
|
||||
keys = [],
|
||||
i;
|
||||
|
||||
// Get and sort keys
|
||||
for (i in value) keys.push(i);
|
||||
keys.sort();
|
||||
|
||||
// Push values
|
||||
for (i = 0; i < keys.length; ++i) {
|
||||
str.push(encode_string(keys[i]));
|
||||
str.push(encode(value[keys[i]]));
|
||||
}
|
||||
|
||||
// End
|
||||
str.push("e");
|
||||
return str.join("");
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Decoding class
|
||||
var Decoder = function () {
|
||||
this.pos = 0;
|
||||
};
|
||||
|
||||
Decoder.prototype = {
|
||||
constructor: Decoder,
|
||||
|
||||
decode: function (str) {
|
||||
// Errors
|
||||
var k = str[this.pos];
|
||||
if (!(k in decode_generic)) throw "Invalid format";
|
||||
|
||||
// Call
|
||||
return decode_generic[k].call(this, str);
|
||||
},
|
||||
decode_int: function (str) {
|
||||
// Skip the "i" prefix
|
||||
++this.pos;
|
||||
|
||||
var end = str.indexOf("e", this.pos),
|
||||
value;
|
||||
|
||||
// No end
|
||||
if (end < 0) throw "Invalid format";
|
||||
|
||||
// Assume proper number format
|
||||
value = parseInt(str.substr(this.pos, end - this.pos), 10);
|
||||
|
||||
// Done
|
||||
this.pos = end + 1;
|
||||
return value;
|
||||
},
|
||||
decode_string: function (str) {
|
||||
var delim = str.indexOf(":", this.pos),
|
||||
length, value;
|
||||
|
||||
// No end
|
||||
if (delim < 0) throw "Invalid format";
|
||||
|
||||
// Assume proper number format
|
||||
length = parseInt(str.substr(this.pos, delim - this.pos), 10);
|
||||
value = str.substr(delim + 1, length);
|
||||
|
||||
// Done
|
||||
this.pos = delim + length + 1;
|
||||
return value;
|
||||
},
|
||||
decode_list: function (str) {
|
||||
// Skip the "l" prefix
|
||||
++this.pos;
|
||||
|
||||
// Read list
|
||||
var list = [],
|
||||
value;
|
||||
|
||||
// Loop until end or exception
|
||||
while (str[this.pos] != "e") {
|
||||
value = this.decode(str); // this throws errors if str[this.pos] is out of bounds
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
// Done; skip "e" suffix
|
||||
++this.pos;
|
||||
return list;
|
||||
},
|
||||
decode_dict: function (str) {
|
||||
// Skip the "d" prefix
|
||||
++this.pos;
|
||||
|
||||
// Read dict
|
||||
var dict = {},
|
||||
key, value;
|
||||
|
||||
// Loop until end or exception
|
||||
while (str[this.pos] != "e") {
|
||||
key = this.decode_string(str);
|
||||
value = this.decode(str); // this throws errors if str[this.pos] is out of bounds
|
||||
dict[key] = value;
|
||||
}
|
||||
|
||||
// Done; skip "e" suffix
|
||||
++this.pos;
|
||||
return dict;
|
||||
},
|
||||
};
|
||||
|
||||
// Generic decode functions
|
||||
var decode_generic = {
|
||||
"l": Decoder.prototype.decode_list,
|
||||
"d": Decoder.prototype.decode_dict,
|
||||
"i": Decoder.prototype.decode_int,
|
||||
},
|
||||
i;
|
||||
for (i = 0; i < 10; ++i) decode_generic[i.toString()] = Decoder.prototype.decode_string;
|
||||
|
||||
|
||||
|
||||
// Encode/decode functions
|
||||
return {
|
||||
/**
|
||||
encode: function (obj)
|
||||
Encodes an object into a Bencode'd string
|
||||
|
||||
@param obj
|
||||
The object to encode
|
||||
This should only be one of the following:
|
||||
string
|
||||
number (floats are floor'd to integers)
|
||||
array (containing things only from this list)
|
||||
object (containing things only from this list)
|
||||
Strings should be encoded in some way such that each character is in the range [0,255]
|
||||
@return
|
||||
A string representing the object
|
||||
*/
|
||||
encode: encode,
|
||||
/**
|
||||
decode: function (str)
|
||||
Decodes a Bencode'd string back into its original type
|
||||
|
||||
@param str
|
||||
The string to decode
|
||||
@return
|
||||
The original object represented by str
|
||||
@throws
|
||||
Any one of the following self-explanatory strings
|
||||
"Invalid format"
|
||||
"Invalid string"
|
||||
"Invalid int"
|
||||
*/
|
||||
decode: function (str) {
|
||||
// Create a decoder and call
|
||||
return (new Decoder()).decode(str);
|
||||
},
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
235
weboasis/torrent/t2m/src/sha1.js
Normal file
235
weboasis/torrent/t2m/src/sha1.js
Normal file
@ -0,0 +1,235 @@
|
||||
|
||||
|
||||
|
||||
// Class for SHA1 computation
|
||||
var SHA1 = (function () {
|
||||
"use strict";
|
||||
|
||||
// Private variables
|
||||
var hash_size = 20,
|
||||
message_block_length = 64,
|
||||
message_block_terminator = 0x80,
|
||||
message_length_bytes = 8,
|
||||
initial_intermediate_hash = new Uint32Array(5),
|
||||
K_constants = new Uint32Array(4);
|
||||
|
||||
initial_intermediate_hash[0] = 0x67452301;
|
||||
initial_intermediate_hash[1] = 0xEFCDAB89;
|
||||
initial_intermediate_hash[2] = 0x98BADCFE;
|
||||
initial_intermediate_hash[3] = 0x10325476;
|
||||
initial_intermediate_hash[4] = 0xC3D2E1F0;
|
||||
|
||||
K_constants[0] = 0x5A827999;
|
||||
K_constants[1] = 0x6ED9EBA1;
|
||||
K_constants[2] = 0x8F1BBCDC;
|
||||
K_constants[3] = 0xCA62C1D6;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
SHA1 instance constructor; creates an empty SHA1 object.
|
||||
|
||||
@return
|
||||
A new SHA1 instance
|
||||
*/
|
||||
var SHA1 = function () {
|
||||
this.length = 0;
|
||||
this.message_block_index = 0;
|
||||
this.message_block = new Uint8Array(message_block_length);
|
||||
this.intermediate_hash = new Uint32Array(initial_intermediate_hash);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Private methods
|
||||
var pad = function () {
|
||||
var maxlen = this.message_block.length - message_length_bytes,
|
||||
high = Math.floor(this.length / 0x0FFFFFFFF) & 0xFFFFFFFF,
|
||||
low = this.length & 0xFFFFFFFF,
|
||||
message_block = this.message_block,
|
||||
message_block_index = this.message_block_index,
|
||||
input_intermediate_hash = this.intermediate_hash,
|
||||
output_intermediate_hash = new Uint32Array(this.intermediate_hash.length);
|
||||
|
||||
// Termination byte
|
||||
message_block[message_block_index] = message_block_terminator;
|
||||
|
||||
// Process another block if there's no space for the length
|
||||
if (message_block_index >= maxlen) {
|
||||
// 0-ify
|
||||
while (++message_block_index < message_block.length) message_block[message_block_index] = 0;
|
||||
|
||||
// Process block
|
||||
process.call(this, message_block, input_intermediate_hash, output_intermediate_hash);
|
||||
|
||||
// Create copies that don't interfere with "this"
|
||||
message_block = new Uint8Array(message_block.length); // no 0-ifying needed
|
||||
input_intermediate_hash = output_intermediate_hash;
|
||||
}
|
||||
else {
|
||||
// 0-ify
|
||||
while (++message_block_index < maxlen) message_block[message_block_index] = 0;
|
||||
}
|
||||
|
||||
// Store length
|
||||
message_block[maxlen] = (high >>> 24) & 0xFF;
|
||||
message_block[++maxlen] = (high >>> 16) & 0xFF;
|
||||
message_block[++maxlen] = (high >>> 8) & 0xFF;
|
||||
message_block[++maxlen] = (high) & 0xFF;
|
||||
message_block[++maxlen] = (low >>> 24) & 0xFF;
|
||||
message_block[++maxlen] = (low >>> 16) & 0xFF;
|
||||
message_block[++maxlen] = (low >>> 8) & 0xFF;
|
||||
message_block[++maxlen] = (low) & 0xFF;
|
||||
|
||||
process.call(this, message_block, input_intermediate_hash, output_intermediate_hash);
|
||||
|
||||
// Return hash
|
||||
return output_intermediate_hash;
|
||||
};
|
||||
var process = function (message_block, intermediate_hash_input, intermediate_hash_output) {
|
||||
var W = new Uint32Array(80),
|
||||
i, i4, temp, A, B, C, D, E;
|
||||
|
||||
// Init W
|
||||
for (i = 0; i < 16; ++i) {
|
||||
i4 = i * 4;
|
||||
W[i] =
|
||||
(message_block[i4] << 24) |
|
||||
(message_block[i4 + 1] << 16) |
|
||||
(message_block[i4 + 2] << 8) |
|
||||
(message_block[i4 + 3]);
|
||||
}
|
||||
for (/*i = 16*/; i < 80; ++i) {
|
||||
W[i] = circular_shift(1, W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]);
|
||||
}
|
||||
|
||||
A = intermediate_hash_input[0];
|
||||
B = intermediate_hash_input[1];
|
||||
C = intermediate_hash_input[2];
|
||||
D = intermediate_hash_input[3];
|
||||
E = intermediate_hash_input[4];
|
||||
|
||||
for (i = 0; i < 20; ++i) {
|
||||
temp = circular_shift(5, A) + ((B & C) | ((~B) & D)) + E + W[i] + K_constants[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = circular_shift(30, B);
|
||||
B = A;
|
||||
A = temp & 0xFFFFFFFF;
|
||||
}
|
||||
for (/*i = 20*/; i < 40; ++i) {
|
||||
temp = circular_shift(5, A) + (B ^ C ^ D) + E + W[i] + K_constants[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = circular_shift(30, B);
|
||||
B = A;
|
||||
A = temp & 0xFFFFFFFF;
|
||||
}
|
||||
for (/*i = 40*/; i < 60; ++i) {
|
||||
temp = circular_shift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[i] + K_constants[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = circular_shift(30, B);
|
||||
B = A;
|
||||
A = temp & 0xFFFFFFFF;
|
||||
}
|
||||
for (/*i = 60*/; i < 80; ++i) {
|
||||
temp = circular_shift(5, A) + (B ^ C ^ D) + E + W[i] + K_constants[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = circular_shift(30, B);
|
||||
B = A;
|
||||
A = temp & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
intermediate_hash_output[0] = intermediate_hash_input[0] + A;
|
||||
intermediate_hash_output[1] = intermediate_hash_input[1] + B;
|
||||
intermediate_hash_output[2] = intermediate_hash_input[2] + C;
|
||||
intermediate_hash_output[3] = intermediate_hash_input[3] + D;
|
||||
intermediate_hash_output[4] = intermediate_hash_input[4] + E;
|
||||
};
|
||||
var circular_shift = function (bits, word) {
|
||||
return (word << bits) | (word >>> (32 - bits));
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Public methods
|
||||
SHA1.prototype = {
|
||||
constructor: SHA1,
|
||||
|
||||
/**
|
||||
Reset the state of the hashing object to its initial state.
|
||||
*/
|
||||
reset: function () {
|
||||
// Reset everything
|
||||
var i;
|
||||
|
||||
this.length = 0;
|
||||
this.message_block_index = 0;
|
||||
|
||||
for (i = 0; i < this.intermediate_hash.length; ++i) {
|
||||
this.intermediate_hash[i] = initial_intermediate_hash[i];
|
||||
}
|
||||
for (i = 0; i < this.message_block.length; ++i) {
|
||||
this.message_block[i] = 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Feed data into the instance to update the hash.
|
||||
|
||||
@param value_array
|
||||
The values to update with. This can either be:
|
||||
- A string (encoded so that every character is in the range [0,255])
|
||||
- A (typed) array
|
||||
*/
|
||||
update: function (value_array) {
|
||||
var is_string = (typeof(value_array) == "string"),
|
||||
i;
|
||||
|
||||
for (i = 0; i < value_array.length; ++i) {
|
||||
// Update block
|
||||
this.message_block[this.message_block_index] = is_string ? value_array.charCodeAt(i) : value_array[i];
|
||||
|
||||
// Update length
|
||||
this.length += 8;
|
||||
|
||||
// Process block
|
||||
if (++this.message_block_index >= this.message_block.length) {
|
||||
process.call(this, this.message_block, this.intermediate_hash, this.intermediate_hash);
|
||||
this.message_block_index = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Computes the SHA1 digest of the data input so far.
|
||||
|
||||
@return
|
||||
A Uint8Array of the computed digest
|
||||
*/
|
||||
digest: function () {
|
||||
// Setup
|
||||
var digest = new Uint8Array(hash_size),
|
||||
intermediate_hash_temp = pad.call(this),
|
||||
i;
|
||||
|
||||
// Hash
|
||||
for (i = 0; i < digest.length; ++i) {
|
||||
digest[i] = intermediate_hash_temp[i >> 2] >> (8 * (3 - (i & 0x03)));
|
||||
}
|
||||
|
||||
// Done
|
||||
return digest;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Return the class object
|
||||
return SHA1;
|
||||
|
||||
})();
|
||||
|
||||
|
102
weboasis/torrent/t2m/src/sha1.test.js
Normal file
102
weboasis/torrent/t2m/src/sha1.test.js
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
|
||||
|
||||
// Functions for testing sha1.js
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// Tests
|
||||
var tests = [
|
||||
{
|
||||
value: "abc",
|
||||
repeat: 1,
|
||||
correct: "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D",
|
||||
},
|
||||
{
|
||||
value: "abcdbcdecdefdefgefghfghighijhi" + "jkijkljklmklmnlmnomnopnopq",
|
||||
repeat: 1,
|
||||
correct: "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1",
|
||||
},
|
||||
{
|
||||
value: "a",
|
||||
repeat: 1000000,
|
||||
correct: "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F",
|
||||
},
|
||||
{
|
||||
value: "01234567012345670123456701234567" + "01234567012345670123456701234567",
|
||||
repeat: 10,
|
||||
correct: "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52",
|
||||
},
|
||||
{
|
||||
value: "a",
|
||||
repeat: 133047678,
|
||||
correct: "94 A8 41 C9 02 1D 23 57 A8 0A 77 60 01 E2 7D 2F 27 93 91 05",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
// Readable hex
|
||||
var digest_to_spaced_hex = function (digest) {
|
||||
// String build
|
||||
var s = [],
|
||||
c, i;
|
||||
|
||||
for (i = 0; i < digest.length; ++i) {
|
||||
if (i > 0) s.push(" ");
|
||||
c = digest[i].toString(16).toUpperCase();
|
||||
if (c.length < 2) s.push("0");
|
||||
s.push(c);
|
||||
}
|
||||
|
||||
return s.join("");
|
||||
};
|
||||
|
||||
|
||||
// Test function
|
||||
var execute_tests = function () {
|
||||
// Vars for testing
|
||||
var sha = new SHA1(),
|
||||
failures = 0,
|
||||
test, digest, i, j;
|
||||
|
||||
// Run tests
|
||||
for (i = 0; i < tests.length; ++i) {
|
||||
test = tests[i];
|
||||
console.log("Test " + (i + 1) + ": " + JSON.stringify(test.value) + " repeated " + test.repeat + " time" + (test.repeat == 1 ? "" : "s"));
|
||||
|
||||
sha.reset();
|
||||
|
||||
for (j = 0; j < test.repeat; ++j) {
|
||||
sha.update(test.value);
|
||||
}
|
||||
|
||||
digest = digest_to_spaced_hex(sha.digest());
|
||||
|
||||
if (digest == test.correct) {
|
||||
console.log("Digest matches: YES");
|
||||
console.log(" " + digest);
|
||||
}
|
||||
else {
|
||||
console.log("Digest matches: NO");
|
||||
console.log(" " + digest + "(calculated)");
|
||||
console.log(" " + test.correct + " (correct)");
|
||||
++failures;
|
||||
}
|
||||
|
||||
console.log("");
|
||||
}
|
||||
|
||||
// Final status
|
||||
if (failures === 0) {
|
||||
console.log("All tests okay");
|
||||
}
|
||||
else {
|
||||
console.log("" + failures + " test" + (failures == 1 ? "" : "s") + " failed");
|
||||
}
|
||||
};
|
||||
|
||||
execute_tests();
|
||||
|
||||
})();
|
||||
|
||||
|
752
weboasis/torrent/t2m/src/t2m.js
Normal file
752
weboasis/torrent/t2m/src/t2m.js
Normal file
@ -0,0 +1,752 @@
|
||||
|
||||
|
||||
|
||||
var T2M = (function () {
|
||||
"use strict";
|
||||
|
||||
// Module for encoding/decoding UTF8
|
||||
var UTF8 = (function () {
|
||||
|
||||
return {
|
||||
/**
|
||||
Encode a string into UTF-8
|
||||
|
||||
@param str
|
||||
The string to convert.
|
||||
This string should be encoded in some way such that each character is in the range [0,255]
|
||||
@return
|
||||
A UTF-8 encoded string
|
||||
*/
|
||||
encode: function (str) {
|
||||
return unescape(encodeURIComponent(str));
|
||||
},
|
||||
/**
|
||||
Decode a string from UTF-8
|
||||
|
||||
@param str
|
||||
A valid UTF-8 string
|
||||
@return
|
||||
The original string
|
||||
*/
|
||||
decode: function (str) {
|
||||
return decodeURIComponent(escape(str));
|
||||
},
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Class for reading .torrent files
|
||||
var Torrent = (function () {
|
||||
|
||||
var Torrent = function () {
|
||||
this.events = {
|
||||
"load": [],
|
||||
"error": [],
|
||||
"read_error": [],
|
||||
"read_abort": [],
|
||||
};
|
||||
this.file_name = null;
|
||||
this.data = null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var on_reader_load = function (event) {
|
||||
// Decode
|
||||
var data_str = event.target.result;
|
||||
|
||||
if (data_str instanceof ArrayBuffer) {
|
||||
// Convert to string
|
||||
var data_str2 = "",
|
||||
i;
|
||||
|
||||
data_str = new Uint8Array(data_str);
|
||||
for (i = 0; i < data_str.length; ++i) {
|
||||
data_str2 += String.fromCharCode(data_str[i]);
|
||||
}
|
||||
|
||||
data_str = data_str2;
|
||||
}
|
||||
|
||||
try {
|
||||
this.data = Bencode.decode(data_str);
|
||||
}
|
||||
catch (e) {
|
||||
// Throw an error
|
||||
this.data = null;
|
||||
this.file_name = null;
|
||||
trigger.call(this, "error", {
|
||||
type: "Bencode error",
|
||||
exception: e,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Loaded
|
||||
trigger.call(this, "load", {});
|
||||
};
|
||||
var on_reader_error = function () {
|
||||
trigger.call(this, "read_error", {});
|
||||
};
|
||||
var on_reader_abort = function () {
|
||||
trigger.call(this, "read_abort", {});
|
||||
};
|
||||
var trigger = function (event, data) {
|
||||
// Trigger an event
|
||||
var callbacks = this.events[event],
|
||||
i;
|
||||
|
||||
for (i = 0; i < callbacks.length; ++i) {
|
||||
callbacks[i].call(this, data, event);
|
||||
}
|
||||
};
|
||||
var no_change = function (x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
var magnet_component_order_default = [ "xt" , "xl" , "dn" , "tr" ];
|
||||
|
||||
var format_uri = function (array_values, encode_fcn) {
|
||||
if (array_values.length <= 1) return encode_fcn(array_values[0]);
|
||||
|
||||
return array_values[0].replace(/\{([0-9]+)\}/, function (match) {
|
||||
return encode_fcn(array_values[parseInt(match[1], 10) + 1] || "");
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Convert URI components object into a magnet URI.
|
||||
This is used to format the same object multiple times without rehashing anything.
|
||||
|
||||
@param link_components
|
||||
An object returned from convert_to_magnet with return_components=true
|
||||
@param custom_name
|
||||
Can take one of the following values:
|
||||
null/undefined: name will remain the same as it originally was
|
||||
string: the custom name to give the magnet URI
|
||||
@param tracker_mode
|
||||
Can take one of the following values:
|
||||
null/undefined/false/number < 0: single tracker only (primary one)
|
||||
true: multiple trackers (without numbered suffix)
|
||||
number >= 0: multiple trackers (with numbered suffix starting at the specified number)
|
||||
@param uri_encode
|
||||
Can take one of the following values:
|
||||
null/undefined/true: encode components using encodeURIComponent
|
||||
false: no encoding; components are left as-is
|
||||
function: custom encoding function
|
||||
@param component_order
|
||||
A list containing the order URI components should appear in.
|
||||
Default is [ "xt" , "xl" , "dn" , "tr" ]
|
||||
null/undefined will use the default
|
||||
@return
|
||||
A formatted URI
|
||||
*/
|
||||
Torrent.components_to_magnet = function (link_components, custom_name, tracker_mode, uri_encode, component_order) {
|
||||
// Vars
|
||||
var link, obj, list1, val, i, j;
|
||||
|
||||
uri_encode = (uri_encode === false) ? no_change : (typeof(uri_encode) == "function" ? uri_encode : encodeURIComponent);
|
||||
component_order = (component_order === null) ? magnet_component_order_default : component_order;
|
||||
|
||||
// Setup
|
||||
if (typeof(custom_name) == "string") {
|
||||
link_components.dn.values = [ custom_name ];
|
||||
}
|
||||
|
||||
link_components.tr.suffix = -1;
|
||||
if (typeof(tracker_mode) == "number") {
|
||||
tracker_mode = Math.floor(tracker_mode);
|
||||
if (tracker_mode >= 0) link_components.tr.suffix = tracker_mode;
|
||||
}
|
||||
else if (tracker_mode === true) {
|
||||
link_components.tr.suffix = -2;
|
||||
}
|
||||
|
||||
// Form into a URL
|
||||
link = "magnet:";
|
||||
val = 0; // number of components added
|
||||
for (i = 0; i < component_order.length; ++i) {
|
||||
if (!(component_order[i] in link_components)) continue; // not valid
|
||||
obj = link_components[component_order[i]];
|
||||
list1 = obj.values;
|
||||
for (j = 0; j < list1.length; ++j) {
|
||||
// Separator
|
||||
link += (val === 0 ? "?" : "&");
|
||||
++val;
|
||||
|
||||
// Key
|
||||
link += component_order[i];
|
||||
|
||||
// Number
|
||||
if (obj.suffix >= 0 && list1.length > 1) {
|
||||
link += ".";
|
||||
link += obj.suffix;
|
||||
++obj.suffix;
|
||||
}
|
||||
|
||||
// Value
|
||||
link += "=";
|
||||
link += format_uri(list1[j], uri_encode);
|
||||
|
||||
// Done
|
||||
if (obj.suffix == -1) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
return link;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Torrent.prototype = {
|
||||
constructor: Torrent,
|
||||
|
||||
read: function (file) {
|
||||
this.data = null;
|
||||
this.file_name = file.name;
|
||||
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.addEventListener("load", on_reader_load.bind(this), false);
|
||||
reader.addEventListener("error", on_reader_error.bind(this), false);
|
||||
reader.addEventListener("abort", on_reader_abort.bind(this), false);
|
||||
|
||||
try {
|
||||
reader.readAsBinaryString(file);
|
||||
}
|
||||
catch (e) {
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
},
|
||||
|
||||
on: function (event, callback) {
|
||||
if (event in this.events) {
|
||||
this.events[event].push(callback);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
off: function (event, callback) {
|
||||
if (event in this.events) {
|
||||
var callbacks = this.events[event],
|
||||
i;
|
||||
|
||||
for (i = 0; i < callbacks.length; ++i) {
|
||||
if (callbacks[i] == callback) {
|
||||
callbacks.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
Convert the torrent data into a magnet link.
|
||||
|
||||
@param custom_name
|
||||
Can take one of the following values:
|
||||
null/undefined: no custom name will be generated, but if the name field is absent, it will be assumed from the original file's name
|
||||
false: no custom name will be generated OR assumed from the original file name
|
||||
string: the custom name to give the magnet URI
|
||||
@param tracker_mode
|
||||
Can take one of the following values:
|
||||
null/undefined/false/number < 0: single tracker only (primary one)
|
||||
true: multiple trackers (without numbered suffix)
|
||||
number >= 0: multiple trackers (with numbered suffix starting at the specified number)
|
||||
@param uri_encode
|
||||
Can take one of the following values:
|
||||
null/undefined/true: encode components using encodeURIComponent
|
||||
false: no encoding; components are left as-is
|
||||
function: custom encoding function
|
||||
@param component_order
|
||||
A list containing the order URI components should appear in.
|
||||
Default is [ "xt" , "xl" , "dn" , "tr" ]
|
||||
null/undefined will use the default
|
||||
@param return_components
|
||||
If true, this returns the link components which can then be used with components_to_magnet
|
||||
@return
|
||||
A formatted URI if return_components is falsy, else an object containing the parts of the link
|
||||
Also can return null if insufficient data is found
|
||||
*/
|
||||
convert_to_magnet: function (custom_name, tracker_mode, uri_encode, component_order, return_components) {
|
||||
// Insufficient data
|
||||
if (this.data === null || !("info" in this.data)) return null;
|
||||
|
||||
// Bencode info
|
||||
var info = this.data.info,
|
||||
info_bencoded = Bencode.encode(info),
|
||||
info_hasher = new SHA1(),
|
||||
link_components = {},
|
||||
info_hash, link, list1, list2, val, i, j;
|
||||
|
||||
// Hash
|
||||
info_hasher.update(info_bencoded);
|
||||
info_hash = info_hasher.digest();
|
||||
info_hash = String.fromCharCode.apply(null, info_hash); // convert to binary string
|
||||
info_hash = Base32.encode(info_hash); // convert to base32
|
||||
|
||||
// Setup link
|
||||
for (i = 0; i < magnet_component_order_default.length; ++i) {
|
||||
link_components[magnet_component_order_default[i]] = {
|
||||
suffix: -1,
|
||||
values: [],
|
||||
};
|
||||
}
|
||||
|
||||
// Create
|
||||
link_components.xt.values.push([ "urn:btih:{0}", info_hash ]);
|
||||
|
||||
if ("length" in info) {
|
||||
link_components.xl.values.push([ info.length ]);
|
||||
}
|
||||
|
||||
if (typeof(custom_name) == "string") {
|
||||
link_components.dn.values.push([ custom_name ]);
|
||||
}
|
||||
else if ("name" in info) {
|
||||
link_components.dn.values.push([ UTF8.decode(info.name) ]);
|
||||
}
|
||||
else if (custom_name !== false && this.file_name) {
|
||||
link_components.dn.values.push([ this.file_name ]);
|
||||
}
|
||||
|
||||
list1 = link_components.tr.values;
|
||||
if ("announce" in this.data) {
|
||||
list1.push([ UTF8.decode(this.data.announce) ]);
|
||||
}
|
||||
if ("announce-list" in this.data && Array.isArray(list2 = this.data["announce-list"])) {
|
||||
// Add more trackers
|
||||
for (i = 0; i < list2.length; ++i) {
|
||||
if (!Array.isArray(list2[i])) continue; // bad data
|
||||
for (j = 0; j < list2[i].length; ++j) {
|
||||
val = UTF8.decode(list2[i][j]);
|
||||
if (list1.indexOf(val) < 0) list1.push([ val ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert
|
||||
if (return_components) return link_components;
|
||||
link = Torrent.components_to_magnet(link_components, null, tracker_mode, uri_encode, component_order);
|
||||
|
||||
// Done
|
||||
return link;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
return Torrent;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Class for enumerating the results in the DOM
|
||||
var Result = (function () {
|
||||
|
||||
var Result = function () {
|
||||
this.torrent_magnet_components = null;
|
||||
|
||||
this.container = null;
|
||||
this.magnet_link = null;
|
||||
this.magnet_link_text = null;
|
||||
this.magnet_textbox = null;
|
||||
this.options_link = null;
|
||||
this.options_container = null;
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var on_options_link_click = function () {
|
||||
if (this.options_container.classList.contains("converted_item_options_container_visible")) {
|
||||
this.options_container.classList.remove("converted_item_options_container_visible");
|
||||
this.magnet_textbox.readOnly = true;
|
||||
}
|
||||
else {
|
||||
this.options_container.classList.add("converted_item_options_container_visible");
|
||||
this.magnet_textbox.readOnly = false;
|
||||
}
|
||||
};
|
||||
|
||||
var on_textbox_click = function () {
|
||||
if (this.magnet_textbox.readOnly) {
|
||||
this.magnet_textbox.select();
|
||||
}
|
||||
};
|
||||
var on_textbox_keydown = function () {
|
||||
if (this.magnet_textbox.readOnly) return;
|
||||
|
||||
setTimeout(on_textbox_update.bind(this), 10);
|
||||
};
|
||||
var on_textbox_change = function () {
|
||||
on_textbox_update.call(this);
|
||||
};
|
||||
var on_textbox_update = function () {
|
||||
// Get value
|
||||
var uri = this.magnet_textbox.value,
|
||||
protocol = "magnet:";
|
||||
|
||||
// Must have correct protocol
|
||||
if (uri.substr(0, protocol.length).toLowerCase() != protocol) {
|
||||
if (uri.length < protocol.length && uri.toLowerCase() == protocol.substr(0, uri.length)) {
|
||||
// Almost correct
|
||||
uri += protocol.substr(uri.length);
|
||||
}
|
||||
else {
|
||||
// Wrong
|
||||
uri = protocol + uri;
|
||||
}
|
||||
}
|
||||
|
||||
// Update
|
||||
this.magnet_link.setAttribute("href", uri);
|
||||
this.magnet_link_text.textContent = uri;
|
||||
};
|
||||
|
||||
var on_option_change = function () {
|
||||
update_links.call(this, true);
|
||||
};
|
||||
|
||||
var update_links = function (update_displays) {
|
||||
// Update magnet links
|
||||
var magnet_uri = "magnet:asdf",
|
||||
tracker_mode = false,
|
||||
order = [ "xt" ];
|
||||
|
||||
if (this.options[0][0][1].checked) {
|
||||
order.push("dn");
|
||||
}
|
||||
if (this.options[1][0][1].checked) {
|
||||
order.push("xl");
|
||||
}
|
||||
if (this.options[2][0][1].checked) {
|
||||
order.push("tr");
|
||||
if (this.options[2][1][1].checked) {
|
||||
tracker_mode = true;
|
||||
if (this.options[2][2][1].checked) {
|
||||
tracker_mode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
magnet_uri = Torrent.components_to_magnet(this.torrent_magnet_components, null, tracker_mode, true, order);
|
||||
|
||||
// Update text/values
|
||||
this.magnet_link.setAttribute("href", magnet_uri);
|
||||
this.magnet_link_text.textContent = magnet_uri;
|
||||
this.magnet_textbox.value = magnet_uri;
|
||||
|
||||
if (!update_displays) return;
|
||||
|
||||
// Update display
|
||||
var i, j, opt_list;
|
||||
for (i = 0; i < this.options.length; ++i) {
|
||||
opt_list = this.options[i];
|
||||
|
||||
for (j = 0; j < opt_list.length; ++j) {
|
||||
if (!opt_list[j][1].checked) {
|
||||
// This is unchecked; modify boxes after
|
||||
opt_list[j][0].classList.add("converted_item_option_part_visible");
|
||||
// Hide
|
||||
while (++j < opt_list.length) {
|
||||
opt_list[j][0].classList.remove("converted_item_option_part_visible");
|
||||
opt_list[j][1].checked = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Result.prototype = {
|
||||
constructor: Result,
|
||||
|
||||
generate: function (torrent_object, parent_node) {
|
||||
var n1, n2, n3, n4, n5, i, j, ev_bind;
|
||||
|
||||
// Clear
|
||||
this.options = [];
|
||||
|
||||
|
||||
//{ Setup DOM nodes
|
||||
this.container = document.createElement("div");
|
||||
this.container.className = "converted_item";
|
||||
|
||||
|
||||
// Title
|
||||
n1 = document.createElement("div");
|
||||
n1.className = "converted_item_title_container";
|
||||
|
||||
n2 = document.createElement("div");
|
||||
n2.className = "converted_item_title";
|
||||
n2.textContent = torrent_object.file_name || (torrent_object.data && torrent_object.data.info ? torrent_object.data.name : null) || ".torrent";
|
||||
|
||||
n1.appendChild(n2);
|
||||
this.container.appendChild(n1);
|
||||
|
||||
// Contents
|
||||
n1 = document.createElement("div");
|
||||
n1.className = "converted_item_contents";
|
||||
|
||||
// Links
|
||||
n2 = document.createElement("div");
|
||||
n2.className = "converted_item_link_container";
|
||||
|
||||
this.magnet_link = document.createElement("a");
|
||||
this.magnet_link.className = "converted_item_link";
|
||||
|
||||
this.magnet_link_text = document.createElement("span");
|
||||
|
||||
this.magnet_link.appendChild(this.magnet_link_text);
|
||||
n2.appendChild(this.magnet_link);
|
||||
|
||||
this.magnet_textbox = document.createElement("input");
|
||||
this.magnet_textbox.className = "converted_item_textbox";
|
||||
this.magnet_textbox.setAttribute("type", "text");
|
||||
this.magnet_textbox.readOnly = true;
|
||||
|
||||
n2.appendChild(this.magnet_textbox);
|
||||
n1.appendChild(n2);
|
||||
|
||||
|
||||
// Options container
|
||||
this.options_container = document.createElement("div");
|
||||
this.options_container.className = "converted_item_options_container";
|
||||
|
||||
// Header
|
||||
n2 = document.createElement("div");
|
||||
n2.className = "converted_item_header";
|
||||
|
||||
n3 = document.createElement("span");
|
||||
n3.className = "converted_item_header_text";
|
||||
n3.textContent = "Options:";
|
||||
|
||||
n2.appendChild(n3);
|
||||
|
||||
this.options_link = document.createElement("a");
|
||||
this.options_link.className = "converted_item_options_toggle";
|
||||
|
||||
n3 = document.createElement("span");
|
||||
this.options_link.appendChild(n3);
|
||||
|
||||
n2.appendChild(this.options_link);
|
||||
this.options_container.appendChild(n2);
|
||||
|
||||
|
||||
// Options
|
||||
n2 = document.createElement("div");
|
||||
n2.className = "converted_item_options";
|
||||
|
||||
// Name
|
||||
this.options.push([]);
|
||||
|
||||
n3 = document.createElement("div");
|
||||
n3.className = "converted_item_option";
|
||||
|
||||
n4 = document.createElement("label");
|
||||
n4.className = "converted_item_option_part converted_item_option_part_visible";
|
||||
|
||||
n5 = document.createElement("input");
|
||||
n5.className = "converted_item_option_checkbox checkbox";
|
||||
n5.setAttribute("type", "checkbox");
|
||||
n5.checked = true;
|
||||
n4.appendChild(n5);
|
||||
|
||||
this.options[this.options.length - 1].push([ n4 , n5 ]);
|
||||
|
||||
n5 = document.createElement("span");
|
||||
n5.className = "converted_item_option_text";
|
||||
n5.textContent = "Include name";
|
||||
n4.appendChild(n5);
|
||||
|
||||
n3.appendChild(n4);
|
||||
n2.appendChild(n3);
|
||||
|
||||
|
||||
// Data length
|
||||
this.options.push([]);
|
||||
|
||||
n3 = document.createElement("div");
|
||||
n3.className = "converted_item_option";
|
||||
|
||||
n4 = document.createElement("label");
|
||||
n4.className = "converted_item_option_part converted_item_option_part_visible";
|
||||
|
||||
n5 = document.createElement("input");
|
||||
n5.className = "converted_item_option_checkbox checkbox";
|
||||
n5.setAttribute("type", "checkbox");
|
||||
n5.checked = true;
|
||||
n4.appendChild(n5);
|
||||
|
||||
this.options[this.options.length - 1].push([ n4 , n5 ]);
|
||||
|
||||
n5 = document.createElement("span");
|
||||
n5.className = "converted_item_option_text";
|
||||
n5.textContent = "Include data length";
|
||||
n4.appendChild(n5);
|
||||
|
||||
n3.appendChild(n4);
|
||||
n2.appendChild(n3);
|
||||
|
||||
|
||||
// Tracker
|
||||
this.options.push([]);
|
||||
|
||||
n3 = document.createElement("div");
|
||||
n3.className = "converted_item_option";
|
||||
|
||||
n4 = document.createElement("label");
|
||||
n4.className = "converted_item_option_part converted_item_option_part_visible";
|
||||
|
||||
n5 = document.createElement("input");
|
||||
n5.className = "converted_item_option_checkbox checkbox";
|
||||
n5.setAttribute("type", "checkbox");
|
||||
n5.checked = true;
|
||||
n4.appendChild(n5);
|
||||
|
||||
this.options[this.options.length - 1].push([ n4 , n5 ]);
|
||||
|
||||
n5 = document.createElement("span");
|
||||
n5.className = "converted_item_option_text";
|
||||
n5.textContent = "Include tracker";
|
||||
n4.appendChild(n5);
|
||||
|
||||
n3.appendChild(n4);
|
||||
|
||||
|
||||
n4 = document.createElement("label");
|
||||
n4.className = "converted_item_option_part converted_item_option_part_visible";
|
||||
|
||||
n5 = document.createElement("input");
|
||||
n5.className = "converted_item_option_checkbox checkbox";
|
||||
n5.setAttribute("type", "checkbox");
|
||||
n5.checked = false;
|
||||
n4.appendChild(n5);
|
||||
|
||||
this.options[this.options.length - 1].push([ n4 , n5 ]);
|
||||
|
||||
n5 = document.createElement("span");
|
||||
n5.className = "converted_item_option_text";
|
||||
n5.textContent = "Allow multiple trackers";
|
||||
n4.appendChild(n5);
|
||||
|
||||
n3.appendChild(n4);
|
||||
|
||||
|
||||
n4 = document.createElement("label");
|
||||
n4.className = "converted_item_option_part";
|
||||
|
||||
n5 = document.createElement("input");
|
||||
n5.className = "converted_item_option_checkbox checkbox";
|
||||
n5.setAttribute("type", "checkbox");
|
||||
n5.checked = false;
|
||||
n4.appendChild(n5);
|
||||
|
||||
this.options[this.options.length - 1].push([ n4 , n5 ]);
|
||||
|
||||
n5 = document.createElement("span");
|
||||
n5.className = "converted_item_option_text";
|
||||
n5.textContent = "Numbered keys";
|
||||
n4.appendChild(n5);
|
||||
|
||||
n3.appendChild(n4);
|
||||
n2.appendChild(n3);
|
||||
|
||||
|
||||
// Add options
|
||||
this.options_container.appendChild(n2);
|
||||
n1.appendChild(this.options_container);
|
||||
|
||||
|
||||
// Done
|
||||
this.container.appendChild(n1);
|
||||
//}
|
||||
|
||||
|
||||
// Data
|
||||
this.torrent_magnet_components = torrent_object.convert_to_magnet(null, false, true, null, true);
|
||||
update_links.call(this, false);
|
||||
|
||||
|
||||
// Events
|
||||
this.options_link.addEventListener("click", on_options_link_click.bind(this), false);
|
||||
this.magnet_textbox.addEventListener("click", on_textbox_click.bind(this), false);
|
||||
this.magnet_textbox.addEventListener("keydown", on_textbox_keydown.bind(this), false);
|
||||
this.magnet_textbox.addEventListener("change", on_textbox_change.bind(this), false);
|
||||
|
||||
ev_bind = on_option_change.bind(this);
|
||||
for (i = 0; i < this.options.length; ++i) {
|
||||
for (j = 0; j < this.options[i].length; ++j) {
|
||||
this.options[i][j][1].addEventListener("change", ev_bind, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Rice and add
|
||||
if (rice_checkboxes) {
|
||||
rice_checkboxes(this.container.querySelectorAll("input[type=checkbox].checkbox"));
|
||||
}
|
||||
if (parent_node) parent_node.appendChild(this.container);
|
||||
|
||||
},
|
||||
update: function () {
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
return Result;
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Other functions
|
||||
var rice_checkboxes = null;
|
||||
var on_torrent_load = function () {
|
||||
var container = document.querySelector(".converted"),
|
||||
result;
|
||||
|
||||
if (container === null) return;
|
||||
|
||||
container.classList.add("converted_visible");
|
||||
|
||||
result = new Result();
|
||||
result.generate(this, container);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Exposed functions
|
||||
var functions = {
|
||||
setup: function (rice_checkboxes_import) {
|
||||
rice_checkboxes = rice_checkboxes_import;
|
||||
},
|
||||
queue_torrent_files: function (files) {
|
||||
// Read files
|
||||
var i, t;
|
||||
|
||||
for (i = 0; i < files.length; ++i) {
|
||||
t = new Torrent();
|
||||
t.on("load", on_torrent_load);
|
||||
t.read(files[i]);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return functions;
|
||||
|
||||
})();
|
||||
|
||||
|
418
weboasis/torrent/t2m/src/t2m.loader.js
Normal file
418
weboasis/torrent/t2m/src/t2m.loader.js
Normal file
@ -0,0 +1,418 @@
|
||||
|
||||
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// Function for performing actions as soon as possible
|
||||
var on_ready = (function () {
|
||||
|
||||
// Vars
|
||||
var callbacks = [],
|
||||
check_interval = null,
|
||||
check_interval_time = 250;
|
||||
|
||||
// Check if ready and run callbacks
|
||||
var callback_check = function () {
|
||||
if (
|
||||
(document.readyState === "interactive" || document.readyState === "complete") &&
|
||||
callbacks !== null
|
||||
) {
|
||||
// Run callbacks
|
||||
var cbs = callbacks,
|
||||
cb_count = cbs.length,
|
||||
i;
|
||||
|
||||
// Clear
|
||||
callbacks = null;
|
||||
|
||||
for (i = 0; i < cb_count; ++i) {
|
||||
cbs[i].call(null);
|
||||
}
|
||||
|
||||
// Clear events and checking interval
|
||||
window.removeEventListener("load", callback_check, false);
|
||||
window.removeEventListener("readystatechange", callback_check, false);
|
||||
|
||||
if (check_interval !== null) {
|
||||
clearInterval(check_interval);
|
||||
check_interval = null;
|
||||
}
|
||||
|
||||
// Okay
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not executed
|
||||
return false;
|
||||
};
|
||||
|
||||
// Listen
|
||||
window.addEventListener("load", callback_check, false);
|
||||
window.addEventListener("readystatechange", callback_check, false);
|
||||
|
||||
// Callback adding function
|
||||
return function (cb) {
|
||||
if (callbacks === null) {
|
||||
// Ready to execute
|
||||
cb.call(null);
|
||||
}
|
||||
else {
|
||||
// Delay
|
||||
callbacks.push(cb);
|
||||
|
||||
// Set a check interval
|
||||
if (check_interval === null && callback_check() !== true) {
|
||||
check_interval = setInterval(callback_check, check_interval_time);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Functions
|
||||
var script_add = (function () {
|
||||
|
||||
var script_on_load = function (state) {
|
||||
// Okay
|
||||
script_remove_event_listeners.call(this, state, true);
|
||||
};
|
||||
var script_on_error = function (state) {
|
||||
// Error
|
||||
script_remove_event_listeners.call(this, state, false);
|
||||
};
|
||||
var script_on_readystatechange = function (state) {
|
||||
if (this.readyState === "loaded" || this.readyState === "complete") {
|
||||
// Okay
|
||||
script_remove_event_listeners.call(this, state, true);
|
||||
}
|
||||
};
|
||||
var script_remove_event_listeners = function (state, okay) {
|
||||
// Remove event listeners
|
||||
this.addEventListener("load", state.on_load, false);
|
||||
this.addEventListener("error", state.on_error, false);
|
||||
this.addEventListener("readystatechange", state.on_readystatechange, false);
|
||||
|
||||
state.on_load = null;
|
||||
state.on_error = null;
|
||||
state.on_readystatechange = null;
|
||||
|
||||
// Trigger
|
||||
if (state.callback) state.callback.call(null, okay, this);
|
||||
|
||||
// Remove
|
||||
var par = this.parentNode;
|
||||
if (par) par.removeChild(this);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return function (url, callback) {
|
||||
var head = document.head,
|
||||
script, state;
|
||||
|
||||
if (!head) {
|
||||
// Callback and done
|
||||
callback.call(null, false, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load state
|
||||
state = {
|
||||
on_load: null,
|
||||
on_error: null,
|
||||
on_readystatechange: null,
|
||||
callback: callback,
|
||||
};
|
||||
|
||||
// New script tag
|
||||
script = document.createElement("script");
|
||||
script.async = true;
|
||||
script.setAttribute("src", url);
|
||||
|
||||
// Events
|
||||
script.addEventListener("load", (state.on_load = script_on_load.bind(script, state)), false);
|
||||
script.addEventListener("error", (state.on_error = script_on_error.bind(script, state)), false);
|
||||
script.addEventListener("readystatechange", (state.on_readystatechange = script_on_readystatechange.bind(script, state)), false);
|
||||
|
||||
// Add
|
||||
head.appendChild(script);
|
||||
|
||||
// Done
|
||||
return true;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
var on_generic_stop_propagation = function (event) {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
var on_exclusive_mode_change = function (flag_node) {
|
||||
exclusive_mode_update.call(this, flag_node, false);
|
||||
};
|
||||
var exclusive_mode_update = (function () {
|
||||
var previous_fragment = "";
|
||||
|
||||
return function (flag_node, check_fragment) {
|
||||
var hash_is_exclusive = (window.location.hash == "#converter.exclusive");
|
||||
|
||||
if (check_fragment) {
|
||||
this.checked = hash_is_exclusive;
|
||||
}
|
||||
else {
|
||||
if (this.checked ^ (!hash_is_exclusive)) {
|
||||
previous_fragment = window.location.hash;
|
||||
}
|
||||
window.history.replaceState({}, "", window.location.pathname + (this.checked ? "#converter.exclusive" : previous_fragment));
|
||||
}
|
||||
|
||||
if (this.checked) {
|
||||
flag_node.classList.add("exclusive_enabled");
|
||||
}
|
||||
else {
|
||||
flag_node.classList.remove("exclusive_enabled");
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
var on_converter_click = function (converter_files_input, event) {
|
||||
if (event.which != 2 && event.which != 3) {
|
||||
converter_files_input.click();
|
||||
}
|
||||
};
|
||||
var on_converter_files_change = function (converter) {
|
||||
// Read
|
||||
on_converter_test_files.call(converter, this.files);
|
||||
|
||||
// Nullify
|
||||
this.value = null;
|
||||
};
|
||||
|
||||
var on_file_dragover = function (converter, event) {
|
||||
if (Array.prototype.indexOf.call(event.dataTransfer.types, "Files") < 0) return;
|
||||
|
||||
converter.classList.add("converter_files_active");
|
||||
if (this === converter) converter.classList.add("converter_files_hover");
|
||||
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
var on_file_dragleave = function (converter, event) {
|
||||
if (Array.prototype.indexOf.call(event.dataTransfer.types, "Files") < 0) return;
|
||||
|
||||
converter.classList.remove("converter_files_hover");
|
||||
if (this !== converter) converter.classList.remove("converter_files_active");
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
var on_file_drop = function (converter, event) {
|
||||
// Reset style
|
||||
converter.classList.remove("converter_files_active");
|
||||
converter.classList.remove("converter_files_hover");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Not over the converter
|
||||
if (this !== converter) return false;
|
||||
|
||||
// Read files
|
||||
on_converter_test_files.call(converter, event.dataTransfer.files);
|
||||
|
||||
// Done
|
||||
return false;
|
||||
};
|
||||
|
||||
var on_converter_test_files = function (files) {
|
||||
// Read
|
||||
var re_ext = /(\.[^\.]*|)$/,
|
||||
read_files = [],
|
||||
ext, i;
|
||||
|
||||
for (i = 0; i < files.length; ++i) {
|
||||
ext = re_ext.exec(files[i].name)[1].toLowerCase();
|
||||
if (ext == ".torrent") {
|
||||
read_files.push(files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to do
|
||||
if (read_files.length === 0) return;
|
||||
|
||||
// Load scripts if necessary
|
||||
load_requirements(function (errors) {
|
||||
if (errors === 0) {
|
||||
// Load
|
||||
var T2M_obj;
|
||||
try {
|
||||
T2M_obj = T2M;
|
||||
}
|
||||
catch(e) {
|
||||
return; // not found
|
||||
}
|
||||
T2M_obj.queue_torrent_files(read_files);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var load_requirements = (function () {
|
||||
|
||||
// Script requirements
|
||||
var requirements = [
|
||||
"src/sha1.js",
|
||||
"src/bencode.js",
|
||||
"src/base32.js",
|
||||
"src/t2m.js",
|
||||
];
|
||||
|
||||
|
||||
var on_all_scripts_loaded = function () {
|
||||
var T2M_obj;
|
||||
try {
|
||||
T2M_obj = T2M;
|
||||
}
|
||||
catch(e) {
|
||||
return; // not found
|
||||
}
|
||||
|
||||
T2M_obj.setup(rice_checkboxes);
|
||||
};
|
||||
var on_script_load = function (state, callback, okay) {
|
||||
if (okay) ++state.okay;
|
||||
|
||||
if (++state.count >= state.total) {
|
||||
// All loaded/errored
|
||||
if (state.total - state.okay === 0) on_all_scripts_loaded();
|
||||
callback.call(null, state.total - state.okay);
|
||||
}
|
||||
};
|
||||
|
||||
// Return the loading function
|
||||
return function (callback) {
|
||||
// Already loaded?
|
||||
if (requirements === null) {
|
||||
// Yes
|
||||
callback.call(null, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var head = document.head,
|
||||
on_load, i;
|
||||
|
||||
if (!head) return false;
|
||||
|
||||
// Load
|
||||
on_load = on_script_load.bind(null, { okay: 0, count: 0, total: requirements.length, }, callback);
|
||||
for (i = 0; i < requirements.length; ++i) {
|
||||
script_add(requirements[i], on_load);
|
||||
}
|
||||
|
||||
// Done
|
||||
requirements = null;
|
||||
return true;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
var restyle_noscript = function () {
|
||||
// Script
|
||||
var nodes = document.querySelectorAll(".script_disabled"),
|
||||
i;
|
||||
|
||||
for (i = 0; i < nodes.length; ++i) {
|
||||
nodes[i].classList.remove("script_visible");
|
||||
}
|
||||
|
||||
nodes = document.querySelectorAll(".script_enabled");
|
||||
for (i = 0; i < nodes.length; ++i) {
|
||||
nodes[i].classList.add("script_visible");
|
||||
}
|
||||
};
|
||||
|
||||
var rice_checkboxes = function (nodes) {
|
||||
var svgns = "http://www.w3.org/2000/svg",
|
||||
i, par, sib, node, n1, n2, n3;
|
||||
|
||||
nodes = nodes || document.querySelectorAll("input[type=checkbox].checkbox");
|
||||
|
||||
for (i = 0; i < nodes.length; ++i) {
|
||||
node = nodes[i];
|
||||
par = node.parentNode;
|
||||
sib = node.nextSibling;
|
||||
|
||||
// Create new checkbox
|
||||
n1 = document.createElement("label");
|
||||
n1.className = node.className;
|
||||
|
||||
n2 = document.createElementNS(svgns, "svg");
|
||||
n2.setAttribute("svgns", svgns);
|
||||
n2.setAttribute("viewBox", "0 0 16 16");
|
||||
|
||||
n3 = document.createElementNS(svgns, "polygon");
|
||||
n3.setAttribute("points", "13,0 16,2 8,16 5,16 0,11 2,8 6,11.5");
|
||||
|
||||
// Re-add
|
||||
n2.appendChild(n3);
|
||||
n1.appendChild(n2);
|
||||
par.insertBefore(n1, node);
|
||||
n1.insertBefore(node, n2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Execute
|
||||
on_ready(function () {
|
||||
// Noscript
|
||||
var nodes, i;
|
||||
|
||||
// Rice
|
||||
restyle_noscript();
|
||||
rice_checkboxes();
|
||||
|
||||
// Stop propagation links
|
||||
nodes = document.querySelectorAll(".link_stop_propagation");
|
||||
for (i = 0; i < nodes.length; ++i) {
|
||||
nodes[i].addEventListener("click", on_generic_stop_propagation, false);
|
||||
}
|
||||
|
||||
// Setup converter
|
||||
var converter = document.querySelector(".converter"),
|
||||
converter_files = document.querySelector(".converter_files_input"),
|
||||
exclusive_mode = document.querySelector("input.converter_exclusive_mode_check"),
|
||||
non_exclusive_body = document.querySelector(".non_exclusive"),
|
||||
body = document.body;
|
||||
|
||||
if (converter !== null) {
|
||||
// File browser
|
||||
if (converter_files !== null) {
|
||||
converter.addEventListener("click", on_converter_click.bind(converter, converter_files), false);
|
||||
converter_files.addEventListener("change", on_converter_files_change.bind(converter_files, converter), false);
|
||||
}
|
||||
|
||||
// File drag/drop events
|
||||
converter.addEventListener("dragover", on_file_dragover.bind(converter, converter), false);
|
||||
converter.addEventListener("dragleave", on_file_dragleave.bind(converter, converter), false);
|
||||
converter.addEventListener("drop", on_file_drop.bind(converter, converter), false);
|
||||
|
||||
body.addEventListener("dragover", on_file_dragover.bind(body, converter), false);
|
||||
body.addEventListener("dragleave", on_file_dragleave.bind(body, converter), false);
|
||||
body.addEventListener("drop", on_file_drop.bind(body, converter), false);
|
||||
|
||||
// Exclusive
|
||||
if (exclusive_mode !== null) {
|
||||
exclusive_mode_update.call(exclusive_mode, non_exclusive_body, true);
|
||||
exclusive_mode.addEventListener("change", on_exclusive_mode_change.bind(exclusive_mode, non_exclusive_body), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
|
617
weboasis/torrent/t2m/style.css
Normal file
617
weboasis/torrent/t2m/style.css
Normal file
@ -0,0 +1,617 @@
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
color: #111111;
|
||||
background-color: #ffffff;
|
||||
font-family: Arial;
|
||||
font-size: 16px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table,tbody,tr,td {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
ol,ul {
|
||||
margin: 0 0 0 1em;
|
||||
padding: 0;
|
||||
}
|
||||
ol>li,ul>li {
|
||||
line-height: 1.5em;
|
||||
}
|
||||
ol>li+li,ul>li+li {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
line-height: 1.5em;
|
||||
position: relative;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
h5 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
font-size: inherit;
|
||||
}
|
||||
input:focus,
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hardlink_text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.hardlink_text:not(:hover)>a.hardlink {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
|
||||
-moz-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
|
||||
-o-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
|
||||
transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0s, visibility 0.25s linear 0s;
|
||||
}
|
||||
a.hardlink {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
top: 0;
|
||||
padding: 0 0.25em 0 0.5em;
|
||||
color: #c8c8c8;
|
||||
font-weight: bold;
|
||||
|
||||
-webkit-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
|
||||
-moz-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
|
||||
-o-transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
|
||||
transition: color 0.25s ease-in-out 0s, opacity 0.25s ease-in-out 0.5s, visibility 0s linear 0.5s;
|
||||
}
|
||||
a.hardlink:hover {
|
||||
text-decoration: none;
|
||||
color: #0280cf;
|
||||
}
|
||||
a.hardlink:after {
|
||||
content: "#";
|
||||
}
|
||||
|
||||
p+p,
|
||||
h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,
|
||||
p+h1,p+h2,p+h3,p+h4,p+h5,p+h6,
|
||||
h4+h6 {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
code.nowrap {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.codeblock {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
display: block;
|
||||
background: #f3f3f3;
|
||||
border: 1px solid #e5e5e5;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding: 0;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
.codeblock_inner {
|
||||
display: inline-block;
|
||||
padding: 0.5em;
|
||||
}
|
||||
.codeblock.codeblock_pre>.codeblock_inner {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
*::selection {
|
||||
color: #ffffff;
|
||||
background: #0280cf;
|
||||
text-shadow: none;
|
||||
}
|
||||
*::-moz-selection {
|
||||
color: #ffffff ;
|
||||
background: #0280cf;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.section_id {
|
||||
}
|
||||
|
||||
.script_disabled {
|
||||
}
|
||||
.script_disabled:not(.script_visible) {
|
||||
display: none;
|
||||
}
|
||||
.script_enabled {
|
||||
}
|
||||
.script_enabled:not(.script_visible) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type=checkbox],
|
||||
input[type=radio] {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
label.checkbox {
|
||||
display: inline-block;
|
||||
width: 0.75em;
|
||||
height: 0.75em;
|
||||
vertical-align: middle;
|
||||
border: 0.09375em solid #111111;
|
||||
border-radius: 0.25em;
|
||||
padding: 0.125em;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
label.checkbox:before {
|
||||
z-index: -1;
|
||||
position: absolute;
|
||||
display: block;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
content: "";
|
||||
border: none;
|
||||
border-radius: 0.125em;
|
||||
background: #ffffff;
|
||||
}
|
||||
label.checkbox:hover:before,
|
||||
label:not([for]):hover label.checkbox:before {
|
||||
border: 0.125em solid #0280cf;
|
||||
}
|
||||
label.checkbox>input[type=checkbox] {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
}
|
||||
label.checkbox>svg {
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
label.checkbox>svg>polygon {
|
||||
fill: #111111;
|
||||
}
|
||||
label.checkbox.delete_checkbox>svg>polygon:not(:first-child) {
|
||||
visibility: hidden;
|
||||
}
|
||||
label.checkbox.delete_checkbox:hover>svg>polygon:first-child,
|
||||
label:not([for]):hover label.checkbox.delete_checkbox>svg>polygon:first-child {
|
||||
visibility: hidden;
|
||||
}
|
||||
label.checkbox.delete_checkbox:hover>svg>polygon:not(:first-child),
|
||||
label:not([for]):hover label.checkbox.delete_checkbox>svg>polygon:not(:first-child) {
|
||||
visibility: visible;
|
||||
}
|
||||
label.checkbox>input[type=checkbox]:checked+svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
color: #0280cf;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a.light_underline {
|
||||
color: #c8c8c8;
|
||||
}
|
||||
a.light_underline>span {
|
||||
color: #0280cf;
|
||||
}
|
||||
a.light_nohover_color_hover {
|
||||
color: #c8c8c8;
|
||||
}
|
||||
a.light_nohover_color_hover:hover {
|
||||
color: #0280cf;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.main {
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
width: 60em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.main.main_no_overflow {
|
||||
overflow: hidden;
|
||||
}
|
||||
.main.body {
|
||||
margin: 0.5em 0 4em 0;
|
||||
}
|
||||
|
||||
.header_bar {
|
||||
position: relative;
|
||||
|
||||
background: #f3f3f3;
|
||||
background: -webkit-linear-gradient(180deg, #f9f9f9, #f3f3f3);
|
||||
background: -moz-linear-gradient(180deg, #f9f9f9, #f3f3f3);
|
||||
background: -o-linear-gradient(180deg, #f9f9f9, #f3f3f3);
|
||||
background: linear-gradient(180deg, #f9f9f9, #f3f3f3);
|
||||
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
.header_table {
|
||||
margin: 0.5em 0;
|
||||
text-align: left;
|
||||
}
|
||||
.header_table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.header_table_cell {
|
||||
width: 0;
|
||||
}
|
||||
.header_table_cell.header_table_cell_full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header_table_name {
|
||||
font-size: 2em;
|
||||
line-height: 1.2em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.header_table_name_user {
|
||||
}
|
||||
.header_table_name_separator {
|
||||
display: inline-block;
|
||||
margin: 0 0.125em;
|
||||
color: #c8c8c8;
|
||||
}
|
||||
.header_table_name_title {
|
||||
}
|
||||
.header_table_name_title>span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header_table_separator {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
font-size: 2em;
|
||||
height: 1.2em;
|
||||
margin: 0 0.5em;
|
||||
border-left: 1px solid #c8c8c8;
|
||||
}
|
||||
|
||||
.header_table_description {
|
||||
line-height: 1.1em;
|
||||
}
|
||||
.header_table_description_name {
|
||||
font-weight: bold;
|
||||
color: #404040;
|
||||
}
|
||||
.header_table_description_body {
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
.header_table_view_on_github {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
margin-left: 1em;
|
||||
text-align: right;
|
||||
}
|
||||
.header_table_view_on_github_line1 {
|
||||
font-size: 0.8em;
|
||||
line-height: 1em;
|
||||
}
|
||||
.header_table_view_on_github_line2 {
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.light {
|
||||
color: #808080;
|
||||
}
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
.converter_exclusive_mode {
|
||||
white-space: nowrap;
|
||||
margin-left: 1em;
|
||||
padding: 0 2em 0 1em;
|
||||
display: inline-block;
|
||||
font-size: 0.5em;
|
||||
font-weight: normal;
|
||||
line-height: 1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.converter_exclusive_mode_text {
|
||||
vertical-align: middle;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease-in-out 0s;
|
||||
-moz-transition: opacity 0.25s ease-in-out 0s;
|
||||
-o-transition: opacity 0.25s ease-in-out 0s;
|
||||
transition: opacity 0.25s ease-in-out 0s;
|
||||
}
|
||||
.converter_exclusive_mode_text:after {
|
||||
content: "exclusive mode";
|
||||
}
|
||||
.converter_exclusive_mode:hover>.converter_exclusive_mode_text {
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
-moz-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
-o-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
transition: opacity 0.25s ease-in-out 0.5s;
|
||||
}
|
||||
.converter_exclusive_mode_check {
|
||||
margin-right: 0.25em;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease-in-out 0s;
|
||||
-moz-transition: opacity 0.25s ease-in-out 0s;
|
||||
-o-transition: opacity 0.25s ease-in-out 0s;
|
||||
transition: opacity 0.25s ease-in-out 0s;
|
||||
}
|
||||
.converter_exclusive_mode:hover>.converter_exclusive_mode_check {
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
-moz-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
-o-transition: opacity 0.25s ease-in-out 0.5s;
|
||||
transition: opacity 0.25s ease-in-out 0.5s;
|
||||
}
|
||||
|
||||
.converter {
|
||||
display: block;
|
||||
padding: 2em;
|
||||
border: 0.25em dashed #c8c8c8;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
-webkit-transition: border-color 0.25s ease-in-out 0s;
|
||||
-moz-transition: border-color 0.25s ease-in-out 0s;
|
||||
-o-transition: border-color 0.25s ease-in-out 0s;
|
||||
transition: border-color 0.25s ease-in-out 0s;
|
||||
background: #f3f3f3;
|
||||
|
||||
}
|
||||
.converter.converter_files_active {
|
||||
border-color: #0280cf;
|
||||
}
|
||||
.converter_container {
|
||||
display: inline-block;
|
||||
padding-right: 3em;
|
||||
}
|
||||
.converter_table {
|
||||
text-align: left;
|
||||
display: table;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.converter_cell {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.converter_cell_left {
|
||||
width: 0;
|
||||
}
|
||||
.converter_cell_right {
|
||||
width: 100%;
|
||||
}
|
||||
.converter_svg_container {
|
||||
width: 8.5em;
|
||||
height: 10em;
|
||||
}
|
||||
.converter_svg_graphic {
|
||||
width: 10em;
|
||||
height: 10em;
|
||||
-webkit-transition: transform 0.25s ease-in-out 0s;
|
||||
-moz-transition: transform 0.25s ease-in-out 0s;
|
||||
-o-transition: transform 0.25s ease-in-out 0s;
|
||||
transition: transform 0.25s ease-in-out 0s;
|
||||
}
|
||||
.converter_svg_graphic_poly {
|
||||
fill: #c8c8c8;
|
||||
stroke: none;
|
||||
-webkit-transition: fill 0.25s ease-in-out 0s;
|
||||
-moz-transition: fill 0.25s ease-in-out 0s;
|
||||
-o-transition: fill 0.25s ease-in-out 0s;
|
||||
transition: fill 0.25s ease-in-out 0s;
|
||||
}
|
||||
.converter_info {
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
}
|
||||
.converter_info_line1 {
|
||||
font-weight: bold;
|
||||
font-size: 4em;
|
||||
line-height: 1em;
|
||||
}
|
||||
.converter_info_line2 {
|
||||
font-size: 2em;
|
||||
line-height: 1em;
|
||||
}
|
||||
.converter_info_line3 {
|
||||
margin-top: 2em;
|
||||
line-height: 1em;
|
||||
color: #a0a0a0;
|
||||
}
|
||||
.converter_files_input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.converter:hover .converter_svg_graphic,
|
||||
.converter.converter_files_hover .converter_svg_graphic {
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
-moz-transform-origin: 50% 50%;
|
||||
-ms-transform-origin: 50% 50%;
|
||||
-o-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
-webkit-transform: scale(1.25);
|
||||
-moz-transform: scale(1.25);
|
||||
-ms-transform: scale(1.25);
|
||||
-o-transform: scale(1.25);
|
||||
transform: scale(1.25);
|
||||
}
|
||||
.converter.converter_files_active .converter_svg_graphic_poly {
|
||||
fill: #0280cf;
|
||||
}
|
||||
|
||||
.converted {
|
||||
margin-top: 2em;
|
||||
}
|
||||
.converted:not(.converted_visible) {
|
||||
display: none;
|
||||
}
|
||||
.converted_item {
|
||||
}
|
||||
.converted_item+.converted_item {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.converted_item_title_container {
|
||||
border-bottom: 0.25em solid #c8c8c8;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.converted_item_title {
|
||||
color: #0280cf;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
line-height: 1.2em;
|
||||
max-height: 2.4em;
|
||||
overflow: hidden;
|
||||
}
|
||||
.converted_item_contents {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
|
||||
.converted_item_link_container {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
a.converted_item_link {
|
||||
font-size: 1.25em;
|
||||
color: #0280cf;
|
||||
white-space: nowrap;
|
||||
}
|
||||
a.converted_item_link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a.converted_item_link>span {
|
||||
color: #111111;
|
||||
}
|
||||
.converted_item_textbox {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0.5em 0 0 0;
|
||||
padding: 0.5em;
|
||||
border: 1px solid #c8c8c8;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
line-height: 1.2em;
|
||||
color: #111111;
|
||||
}
|
||||
.converted_item_textbox[readonly] {
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
.converted_item_header {
|
||||
margin: 0;
|
||||
}
|
||||
.converted_item_header_text {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
.converted_item_options_container:not(.converted_item_options_container_visible)>.converted_item_header>.converted_item_header_text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a.converted_item_options_toggle {
|
||||
color: #0280cf;
|
||||
display: inline-block;
|
||||
}
|
||||
.converted_item_options_container.converted_item_options_container_visible>.converted_item_header>a.converted_item_options_toggle {
|
||||
margin-left: 1em;
|
||||
}
|
||||
a.converted_item_options_toggle>span {
|
||||
color: #c8c8c8;
|
||||
}
|
||||
a.converted_item_options_toggle:hover>span {
|
||||
color: #111111;
|
||||
}
|
||||
a.converted_item_options_toggle>span:after {
|
||||
content: "Show options";
|
||||
}
|
||||
.converted_item_options_container.converted_item_options_container_visible>.converted_item_header>a.converted_item_options_toggle>span:after {
|
||||
content: "Hide";
|
||||
}
|
||||
|
||||
.converted_item_options_container {
|
||||
}
|
||||
.converted_item_options {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.converted_item_options_container:not(.converted_item_options_container_visible)>.converted_item_options {
|
||||
display: none;
|
||||
}
|
||||
.converted_item_option {
|
||||
}
|
||||
.converted_item_option+.converted_item_option {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.converted_item_option_part {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
.converted_item_option_part+.converted_item_option_part {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.converted_item_option_part:not(.converted_item_option_part_visible) {
|
||||
display: none;
|
||||
}
|
||||
.converted_item_option_checkbox {
|
||||
vertical-align: middle;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
.converted_item_option_text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.non_exclusive {
|
||||
margin-top: 2em;
|
||||
}
|
||||
.non_exclusive.exclusive_enabled {
|
||||
display: none;
|
||||
}
|
83
weboasis/torrent/views/download.html
Normal file
83
weboasis/torrent/views/download.html
Normal file
@ -0,0 +1,83 @@
|
||||
<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 & Press Enter</label>
|
||||
<input type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%"/>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Otherwise Upload Torrent File Below</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</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>
|
63
weboasis/torrent/views/full.html
Normal file
63
weboasis/torrent/views/full.html
Normal file
@ -0,0 +1,63 @@
|
||||
<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.paused" ng-click="$root.selectedTorrent.pause()"><i class="fa fa-pause"></i> Pause</button>
|
||||
<button ng-if="$root.selectedTorrent.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</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>
|
11
weboasis/torrent/views/view.html
Normal file
11
weboasis/torrent/views/view.html
Normal file
@ -0,0 +1,11 @@
|
||||
<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>Stream/View: Torrent Must Contain Files That Can Play Within Browser Like MP3 or MP4<br />Example Hash: 08ada5a7a6183aae1e09d831df6748d566095a10</label>
|
||||
<input type="text" placeholder="magnet, hash or http(s) .torrent" ng-model="torrentInput" ng-disabled="$root.disabled" style="width: 50%"/>
|
||||
</form>
|
||||
</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>
|
Reference in New Issue
Block a user