-
Notifications
You must be signed in to change notification settings - Fork 975
Support .torrent files in Torrent Viewer #7351
Changes from all commits
866019a
13475b5
9b5061d
2fefbf2
ef21ddc
b81798f
fad4acf
e770256
6df2507
fabc31b
b790137
9c44d03
a03d8c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,10 +10,10 @@ | |
<link rel="shortcut icon" type="image/x-icon" href="img/webtorrent-128.png"> | ||
<title data-l10n-id="webtorrentPage"></title> | ||
<script src="ext/l20n.min.js"></script> | ||
<script src='gen/webtorrentPage.entry.js'></script> | ||
<link rel="localization" href="locales/{locale}/app.properties"> | ||
</head> | ||
<body> | ||
<div id="appContainer" /> | ||
<script src='gen/webtorrentPage.entry.js'></script> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This let's us use the DOM node |
||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const React = require('react') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pulled this into its own component |
||
|
||
const MediaViewer = require('./mediaViewer') | ||
const TorrentViewer = require('./torrentViewer') | ||
|
||
class App extends React.Component { | ||
render () { | ||
const { | ||
ix, | ||
name, | ||
torrentId, | ||
torrentIdProtocol, | ||
torrent, | ||
serverUrl, | ||
errorMessage | ||
} = this.props.store | ||
|
||
if (torrent && ix != null) { | ||
return <MediaViewer torrent={torrent} serverUrl={serverUrl} ix={ix} /> | ||
} else { | ||
return ( | ||
<TorrentViewer | ||
name={name} | ||
torrentId={torrentId} | ||
torrentIdProtocol={torrentIdProtocol} | ||
torrent={torrent} | ||
serverUrl={serverUrl} | ||
errorMessage={errorMessage} | ||
dispatch={this.props.dispatch} /> | ||
) | ||
} | ||
} | ||
} | ||
|
||
module.exports = App |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,24 +19,26 @@ const SUPPORTED_AUDIO_EXTENSIONS = [ | |
|
||
module.exports = class MediaViewer extends React.Component { | ||
render () { | ||
const torrent = this.props.torrent | ||
const ix = this.props.ix | ||
const { torrent, serverUrl, ix } = this.props | ||
|
||
const file = torrent.files[ix] | ||
const fileURL = serverUrl && (serverUrl + '/' + ix) | ||
|
||
const fileExt = file && getExtension(file.name) | ||
const isVideo = SUPPORTED_VIDEO_EXTENSIONS.includes(fileExt) | ||
const isAudio = SUPPORTED_AUDIO_EXTENSIONS.includes(fileExt) | ||
const fileURL = torrent.serverURL && (torrent.serverURL + '/' + ix) | ||
|
||
let content | ||
if (torrent.serverURL == null) { | ||
if (!file || !serverUrl) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix race condition where media is briefly added to <iframe>. If there is no file object yet, but there is a serverUrl, then an iframe is added to the page, instead of a "Loading..." message. |
||
content = <div data-l10n-id='torrentLoadingMedia' /> | ||
} else if (isVideo) { | ||
content = <video src={fileURL} autoPlay controls /> | ||
} else if (isAudio) { | ||
content = <audio src={fileURL} autoPlay controls /> | ||
} else { | ||
// For security, sandbox and disallow scripts. | ||
// We need allow-same-origin so that the iframe can load from http://localhost:... | ||
// We need allow-same-origin so that the iframe can load from | ||
// http://localhost:... | ||
content = <iframe src={fileURL} sandbox='allow-same-origin' /> | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ const SortableTable = require('../../components/sortableTable') | |
|
||
class TorrentFileList extends React.Component { | ||
render () { | ||
const torrent = this.props.torrent | ||
const { torrent, stateOwner } = this.props | ||
const files = torrent && torrent.files | ||
|
||
let content | ||
|
@@ -27,7 +27,7 @@ class TorrentFileList extends React.Component { | |
rowObjects={files} | ||
columnClassNames={['num', 'name', 'downloadFile', 'size']} | ||
addHoverClass | ||
stateOwner={this.props.stateOwner} /> | ||
stateOwner={stateOwner} /> | ||
] | ||
} | ||
|
||
|
@@ -40,18 +40,21 @@ class TorrentFileList extends React.Component { | |
} | ||
|
||
renderFileLink (file, isDownload) { | ||
const { torrent, torrentID } = this.props | ||
const { torrentId, torrent, serverUrl } = this.props | ||
const ix = torrent.files.indexOf(file) | ||
if (isDownload) { | ||
if (torrent.serverURL) { | ||
const httpURL = torrent.serverURL + '/' + ix | ||
if (serverUrl) { | ||
const httpURL = serverUrl + '/' + ix | ||
return <a href={httpURL} download={file.name}>⇩</a> | ||
} else { | ||
return <div /> // No download links until the server is ready | ||
} | ||
} else { | ||
const magnetURL = torrentID + '&ix=' + ix | ||
return <a href={magnetURL}>{file.name}</a> | ||
const suffix = /^https?:/.test(torrentId) | ||
? '#ix=' + ix | ||
: '&ix=' + ix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For http torrent links, we use a hash symbol instead of a query param to indicate the file that is selected, since we don't want to add random query params to the URL, which could cause the server to 404 if it doesn't like it. For magnet links, adding a query param is acceptable since unknown keys are ignored by all torrent clients. |
||
const href = torrentId + suffix | ||
return <a href={href}>{file.name}</a> | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,9 +12,18 @@ class TorrentViewer extends React.Component { | |
} | ||
|
||
render () { | ||
const {torrent, torrentID, name, errorMessage, dispatch} = this.props | ||
const { | ||
name, | ||
torrentId, | ||
torrent, | ||
serverUrl, | ||
errorMessage, | ||
torrentIdProtocol, | ||
dispatch | ||
} = this.props | ||
|
||
let titleElem, mainButtonId, saveButton | ||
|
||
let titleElem, mainButtonId | ||
if (torrent) { | ||
if (name) { | ||
// No localization, just use the torrent name | ||
|
@@ -36,6 +45,24 @@ class TorrentViewer extends React.Component { | |
mainButtonId = 'startDownload' | ||
} | ||
|
||
if (torrentIdProtocol === 'magnet:') { | ||
saveButton = ( | ||
<Button | ||
l10nId='copyMagnetLink' | ||
className='whiteButton copyMagnetLink' | ||
onClick={() => dispatch('copyMagnetLink')} | ||
/> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Magnet links get a "Copy Magnet Link" button, instead of "Save Torrent File" which made no sense. |
||
) | ||
} else { | ||
saveButton = ( | ||
<Button | ||
l10nId='saveTorrentFile' | ||
className='whiteButton saveTorrentFile' | ||
onClick={() => dispatch('saveTorrentFile')} | ||
/> | ||
) | ||
} | ||
|
||
const legalNotice = torrent != null | ||
? <a className='legalNotice' data-l10n-id='poweredByWebTorrent' href='https://webtorrent.io' target='_blank' /> | ||
: <div className='legalNotice' data-l10n-id='legalNotice' /> | ||
|
@@ -49,20 +76,20 @@ class TorrentViewer extends React.Component { | |
l10nId={mainButtonId} | ||
className='primaryButton mainButton' | ||
disabled={!!torrent} | ||
onClick={() => dispatch('start')} /> | ||
<Button | ||
l10nId='saveTorrentFile' | ||
className='whiteButton saveTorrentFile' | ||
onClick={() => dispatch('saveTorrentFile')} /> | ||
onClick={() => dispatch('start')} | ||
/> | ||
{saveButton} | ||
</div> | ||
</div> | ||
|
||
<div className='siteDetailsPageContent'> | ||
<TorrentStatus torrent={torrent} errorMessage={errorMessage} /> | ||
<TorrentFileList | ||
torrentId={torrentId} | ||
torrent={torrent} | ||
serverUrl={serverUrl} | ||
stateOwner={this} | ||
torrentID={torrentID} /> | ||
/> | ||
{legalNotice} | ||
</div> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This .torrent file detection is pretty conservative. It looks for a torrent mimetype, and only uses the ".torrent" extension to indicate a torrent if the server sets the 'content-type' to 'application/octet-stream'.