Partially implement BEP 53

This enables `--select-only 1,2,3` which gets appended to the magnet
link as `&so=1,2,3`.

It's a partial implementation because we're missing support for file
ranges ie `--select-only 4-6`

type: added
fixes:
- https://github.com/casey/intermodal/issues/245
This commit is contained in:
strickinato 2020-04-12 19:50:00 -07:00 committed by Casey Rodarmor
parent 6185d6c8a2
commit cb8b5a6919
No known key found for this signature in database
GPG Key ID: 556186B153EC6FE0
10 changed files with 116 additions and 14 deletions

View File

@ -2,9 +2,10 @@ Changelog
=========
UNRELEASED - 2020-04-12
UNRELEASED - 2020-04-13
-----------------------
- :books: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Add table of packages to readme ([#372](https://github.com/casey/intermodal/pull/372)) - Fixes [#369](https://github.com/casey/intermodal/issues/369) - _Casey Rodarmor <casey@rodarmor.com>_
- :sparkles: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Partially implement BEP 53 - Fixes [#245](https://github.com/casey/intermodal/issues/245) - _strickinato <aaronstrick@gmail.com>_
- :books: [`6185d6c8a27c`](https://github.com/casey/intermodal/commit/6185d6c8a27c0d603f0434e98000c8e4a868dcc8) Add table of packages to readme ([#372](https://github.com/casey/intermodal/pull/372)) - Fixes [#369](https://github.com/casey/intermodal/issues/369) - _Casey Rodarmor <casey@rodarmor.com>_
- :wrench: [`ddf097c83690`](https://github.com/casey/intermodal/commit/ddf097c8369002748992165f81e9a1bdbe6eff98) Fix `publish` recipe ([#368](https://github.com/casey/intermodal/pull/368)) - _Casey Rodarmor <casey@rodarmor.com>_

View File

@ -14,8 +14,12 @@ FLAGS:
-V, --version Print version number.
OPTIONS:
-i, --input <METAINFO> Generate magnet link from metainfo at `PATH`. If
`PATH` is `-`, read metainfo from standard input.
-p, --peer <PEER>... Add `PEER` to magnet link.
-s, --select-only <INDICES>...
Specify files that torrent clients select for download. Values are
indices into the info.files list. e.g. `--select-only 1,2,3`
-i, --input <METAINFO>
Generate magnet link from metainfo at `PATH`. If `PATH` is `-`, read
metainfo from standard input.
-p, --peer <PEER>... Add `PEER` to magnet link.
```

View File

@ -245,7 +245,7 @@ _imdl() {
return 0
;;
imdl__torrent__link)
opts=" -O -h -V -i -p --open --help --version --input --peer "
opts=" -O -h -V -i -p -s --open --help --version --input --peer --select-only "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -268,6 +268,14 @@ _imdl() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--select-only)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-s)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;

View File

@ -124,8 +124,10 @@ Sort in ascending order by size, break ties in descending path order:
cand --input 'Generate magnet link from metainfo at `PATH`. If `PATH` is `-`, read metainfo from standard input.'
cand -p 'Add `PEER` to magnet link.'
cand --peer 'Add `PEER` to magnet link.'
cand -O 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows'
cand --open 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows'
cand -s 'Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.'
cand --select-only 'Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.'
cand -O 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.'
cand --open 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.'
cand -h 'Print help message.'
cand --help 'Print help message.'
cand -V 'Print version number.'

View File

@ -69,7 +69,8 @@ complete -c imdl -n "__fish_seen_subcommand_from create" -l help -d 'Print help
complete -c imdl -n "__fish_seen_subcommand_from create" -s V -l version -d 'Print version number.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s i -l input -d 'Generate magnet link from metainfo at `PATH`. If `PATH` is `-`, read metainfo from standard input.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s p -l peer -d 'Add `PEER` to magnet link.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s O -l open -d 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows'
complete -c imdl -n "__fish_seen_subcommand_from link" -s s -l select-only -d 'Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s O -l open -d 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s h -l help -d 'Print help message.'
complete -c imdl -n "__fish_seen_subcommand_from link" -s V -l version -d 'Print version number.'
complete -c imdl -n "__fish_seen_subcommand_from piece-length" -s h -l help -d 'Print help message.'

View File

@ -132,8 +132,10 @@ Sort in ascending order by size, break ties in descending path order:
[CompletionResult]::new('--input', 'input', [CompletionResultType]::ParameterName, 'Generate magnet link from metainfo at `PATH`. If `PATH` is `-`, read metainfo from standard input.')
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Add `PEER` to magnet link.')
[CompletionResult]::new('--peer', 'peer', [CompletionResultType]::ParameterName, 'Add `PEER` to magnet link.')
[CompletionResult]::new('-O', 'O', [CompletionResultType]::ParameterName, 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows')
[CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows')
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.')
[CompletionResult]::new('--select-only', 'select-only', [CompletionResultType]::ParameterName, 'Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.')
[CompletionResult]::new('-O', 'O', [CompletionResultType]::ParameterName, 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.')
[CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.')
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help message.')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help message.')
[CompletionResult]::new('-V', 'V', [CompletionResultType]::ParameterName, 'Print version number.')

View File

@ -135,8 +135,10 @@ _arguments "${_arguments_options[@]}" \
'--input=[Generate magnet link from metainfo at `PATH`. If `PATH` is `-`, read metainfo from standard input.]' \
'*-p+[Add `PEER` to magnet link.]' \
'*--peer=[Add `PEER` to magnet link.]' \
'-O[Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows]' \
'--open[Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows]' \
'*-s+[Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.]' \
'*--select-only=[Select files to download. Values are indices into the `info.files` list, e.g. `--select-only 1,2,3`.]' \
'-O[Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.]' \
'--open[Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; `open` on macOS; and `cmd /C start` on Windows.]' \
'-h[Print help message.]' \
'--help[Print help message.]' \
'-V[Print version number.]' \

View File

@ -19,6 +19,10 @@ and `cmd \fI\,/C\/\fP start` on Windows
Print version number.
.SH "OPTIONS:"
.TP
\fB\-s\fR, \fB\-\-select\-only\fR <INDICES>...
Specify files that torrent clients select for download. Values are indices into
the info.files list. e.g. `\-\-select\-only 1,2,3`
.TP
\fB\-i\fR, \fB\-\-input\fR <METAINFO>
Generate magnet link from metainfo at `PATH`. If `PATH` is `\-`, read metainfo from
standard input.

View File

@ -5,6 +5,7 @@ pub(crate) struct MagnetLink {
name: Option<String>,
peers: Vec<HostPort>,
trackers: Vec<Url>,
indices: BTreeSet<u64>,
}
impl MagnetLink {
@ -26,6 +27,7 @@ impl MagnetLink {
name: None,
peers: Vec::new(),
trackers: Vec::new(),
indices: BTreeSet::new(),
}
}
@ -43,6 +45,10 @@ impl MagnetLink {
self.trackers.push(tracker);
}
pub(crate) fn add_index(&mut self, index: u64) {
self.indices.insert(index);
}
pub(crate) fn to_url(&self) -> Url {
let mut url = Url::parse("magnet:").unwrap();
@ -63,6 +69,16 @@ impl MagnetLink {
query.push_str(&peer.to_string());
}
if !self.indices.is_empty() {
query.push_str("&so=");
for (i, selection_index) in self.indices.iter().enumerate() {
if i > 0 {
query.push(',');
}
query.push_str(&selection_index.to_string());
}
}
url.set_query(Some(&query));
url
@ -129,6 +145,19 @@ mod tests {
);
}
#[test]
fn with_indices() {
let mut link = MagnetLink::with_infohash(Infohash::from_bencoded_info_dict("".as_bytes()));
link.add_index(4);
link.add_index(6);
link.add_index(6);
link.add_index(2);
assert_eq!(
link.to_url().as_str(),
"magnet:?xt=urn:btih:da39a3ee5e6b4b0d3255bfef95601890afd80709&so=2,4,6"
);
}
#[test]
fn complex() {
let mut link = MagnetLink::with_infohash(Infohash::from_bencoded_info_dict("".as_bytes()));

View File

@ -21,7 +21,7 @@ pub(crate) struct Link {
long = "open",
short = "O",
help = "Open generated magnet link. Uses `xdg-open`, `gnome-open`, or `kde-open` on Linux; \
`open` on macOS; and `cmd /C start` on Windows"
`open` on macOS; and `cmd /C start` on Windows."
)]
open: bool,
#[structopt(
@ -31,6 +31,15 @@ pub(crate) struct Link {
help = "Add `PEER` to magnet link."
)]
peers: Vec<HostPort>,
#[structopt(
long = "select-only",
short = "s",
value_name = "INDICES",
use_delimiter = true,
help = "Select files to download. Values are indices into the `info.files` list, e.g. \
`--select-only 1,2,3`."
)]
indices: Vec<u64>,
}
impl Link {
@ -52,6 +61,10 @@ impl Link {
link.add_peer(peer);
}
for index in self.indices {
link.add_index(index);
}
let url = link.to_url();
outln!(env, "{}", url)?;
@ -194,6 +207,42 @@ mod tests {
);
}
#[test]
fn with_indices() {
let mut env = test_env! {
args: [
"torrent",
"link",
"--input",
"foo.torrent",
"--select-only",
"2,4",
"--select-only",
"4,6",
],
tree: {
"foo.torrent": "d\
8:announce24:https://foo.com/announce\
4:infod6:lengthi0e4:name3:foo12:piece lengthi1e6:pieces0:e\
e",
}
};
env.assert_ok();
const INFO: &str = "d6:lengthi0e4:name3:foo12:piece lengthi1e6:pieces0:e";
let infohash = Sha1Digest::from_data(INFO.as_bytes());
assert_eq!(
env.out(),
format!(
"magnet:?xt=urn:btih:{}&dn=foo&tr=https://foo.com/announce&so=2,4,6\n",
infohash
),
);
}
#[test]
fn infohash_correct_with_nonstandard_info_dict() {
let mut env = test_env! {