feat: support multiple magnets on the same line (#6465)

This commit is contained in:
Cœur 2024-02-12 02:05:03 +01:00 committed by GitHub
parent ee1e762394
commit 3f71114691
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 23 additions and 15 deletions

View File

@ -1697,29 +1697,37 @@ void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness status, bool
return;
}
// 2. If Pasteboard contains String objects, we'll search for magnet or links
// 2. If Pasteboard contains String objects, we'll search for both links and magnets
NSArray<NSString*>* arrayOfStrings = [NSPasteboard.generalPasteboard readObjectsForClasses:@[ [NSString class] ] options:nil];
if (arrayOfStrings.count == 0)
{
return;
}
NSDataDetector* detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
// The link detector (can't detect magnets)
NSDataDetector* linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
// The magnet detector
// https://www.bittorrent.org/beps/bep_0009.html defines the magnet URI format as `magnet:?query` where query is non-empty.
// https://datatracker.ietf.org/doc/html/rfc3986 defines the query format rigorously as `([!$\&-;=?-Z_a-z~]|%[0-9A-F]{2})*`.
// But `tr_urlParse` acknowledges that magnet links can be malformed by "not escaping text in the display name".
// Those malformed magnets aren't URI anymore, and since a display name can potentially contain any Unicode except '/' (see `isUnixReservedChar`), we may want to be liberal on what we accept.
// In practice, copy-pasted magnets might most often be separated by Horizontal tab, Line feed, Carriage Return, Space, XML delimiters '<' '>', JSON delimiter '"' and Markdown delimiter '`'.
// But for now, we'll keep the historical separator choice from 8392476b30491ffe7d8d64210f5cf3c3dd1d69ca, whitespaceAndNewlineCharacterSet, which is `[\p{Z}\v]`.
NSRegularExpression* magnetDetector = [NSRegularExpression regularExpressionWithPattern:@"magnet:?([^\\p{Z}\\v])+" options:kNilOptions
error:nil];
for (NSString* itemString in arrayOfStrings)
{
NSArray<NSString*>* itemLines = [itemString componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet];
for (__strong NSString* pbItem in itemLines)
// We open all links
for (NSTextCheckingResult* result in [linkDetector matchesInString:itemString options:0
range:NSMakeRange(0, itemString.length)])
{
pbItem = [pbItem stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if ([pbItem rangeOfString:@"magnet:" options:(NSAnchoredSearch | NSCaseInsensitiveSearch)].location != NSNotFound)
{
[self openURL:pbItem];
}
else
{
#warning only accept full text?
for (NSTextCheckingResult* result in [detector matchesInString:pbItem options:0 range:NSMakeRange(0, pbItem.length)])
[self openURL:result.URL.absoluteString];
}
[self openURL:result.URL.absoluteString];
}
// We open all magnets
for (NSTextCheckingResult* result in [magnetDetector matchesInString:itemString options:0
range:NSMakeRange(0, itemString.length)])
{
[self openURL:[itemString substringWithRange:result.range]];
}
}
}