Skip to content

Commit 7d069fb

Browse files
author
Meyn
committed
Fix unknown MP3 and remove from download queue
1 parent e0caebe commit 7d069fb

File tree

9 files changed

+29
-31
lines changed

9 files changed

+29
-31
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
Here’s the complete README with the added short notice under the **Troubleshooting** section:
21
# Tubifarry for Lidarr 🎶
32
![Downloads](https://img.shields.io/github/downloads/TypNull/Tubifarry/total) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/TypNull/Tubifarry) ![GitHub last commit](https://img.shields.io/github/last-commit/TypNull/Tubifarry) ![License](https://img.shields.io/github/license/TypNull/Tubifarry) ![GitHub stars](https://img.shields.io/github/stars/TypNull/Tubifarry)
43

Tubifarry/Core/AlbumData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private string ConstructTitle()
8989
if (calculatedBitrate <= 0 && Size.HasValue && Duration > 0)
9090
calculatedBitrate = (int)((Size.Value * 8) / (Duration * 1000));
9191

92-
if (AudioFormatHelper.IsLossyFormat(Codec))
92+
if (AudioFormatHelper.IsLossyFormat(Codec) && calculatedBitrate != 0)
9393
title += $" [{Codec} {calculatedBitrate}kbps] [WEB]";
9494
else
9595
title += $" [{Codec}] [WEB]";

Tubifarry/Core/AudioFormat.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ internal static class AudioFormatHelper
3131
AudioFormat.WMA
3232
};
3333

34+
35+
private static readonly int[] _standardBitrates = { 0, 96, 128, 160, 192, 256, 320 };
36+
3437
/// <summary>
3538
/// Returns the correct file extension for a given audio codec.
3639
/// </summary>
@@ -121,5 +124,8 @@ internal static class AudioFormatHelper
121124
"wma" => AudioFormat.WMA,
122125
_ => AudioFormat.Unknown // Default for unknown extensions
123126
};
127+
128+
129+
public static int RoundToStandardBitrate(int bitrateKbps) => _standardBitrates.OrderBy(b => Math.Abs(b - bitrateKbps)).First();
124130
}
125131
}

Tubifarry/Download/Clients/Soulseek/SlskdClient.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ namespace NzbDrone.Core.Download.Clients.Soulseek
1616
public class SlskdClient : DownloadClientBase<SlskdProviderSettings>
1717
{
1818
private readonly IHttpClient _httpClient;
19-
private readonly IHistoryService _historyService;
2019

2120
private static readonly Dictionary<DownloadKey, SlskdDownloadItem> _downloadMappings = new();
2221

2322
public override string Name => "Slskd";
2423
public override string Protocol => nameof(SoulseekDownloadProtocol);
2524

26-
public SlskdClient(IHttpClient httpClient, IConfigService configService, IDiskProvider diskProvider,IHistoryService history, IRemotePathMappingService remotePathMappingService, Logger logger)
27-
: base(configService, diskProvider, remotePathMappingService, logger) { _httpClient = httpClient; _historyService = history; }
25+
public SlskdClient(IHttpClient httpClient, IConfigService configService, IDiskProvider diskProvider, IHistoryService history, IRemotePathMappingService remotePathMappingService, Logger logger)
26+
: base(configService, diskProvider, remotePathMappingService, logger) => _httpClient = httpClient;
2827

2928

3029
public override async Task<string> Download(RemoteAlbum remoteAlbum, IIndexer indexer)
@@ -56,7 +55,7 @@ public override void RemoveItem(DownloadClientItem clientItem, bool deleteData)
5655
if (!deleteData) return;
5756
SlskdDownloadItem? slskdItem = GetDownloadItem(clientItem.DownloadId);
5857
if (slskdItem == null) return;
59-
RemoveItemAsync(slskdItem).Wait();
58+
_ = RemoveItemAsync(slskdItem);
6059
RemoveDownloadItem(clientItem.DownloadId);
6160
}
6261

@@ -203,14 +202,20 @@ private HttpRequest BuildHttpRequest(string endpoint, HttpMethod? method = null,
203202
return request;
204203
}
205204

206-
private async Task RemoveItemAsync(SlskdDownloadItem item)
205+
private async Task RemoveItemAsync(SlskdDownloadItem downloadItem)
207206
{
208-
HttpResponse response = await _httpClient.ExecuteAsync(BuildHttpRequest($"/api/v0/transfers/downloads/{item.Username}/{item.ID}", HttpMethod.Delete));
207+
List<SlskdDownloadFile> files = downloadItem.SlskdDownloadDirectory?.Files ?? new List<SlskdDownloadFile>();
209208

210-
if (response.StatusCode != HttpStatusCode.NoContent)
211-
_logger.Warn($"Failed to remove download with ID {item.ID}. Status Code: {response.StatusCode}");
212-
else
213-
_logger.Trace($"Successfully removed download with ID {item.ID}.");
209+
await Task.WhenAll(files.Select(async file =>
210+
{
211+
if (!file.State.Contains("Completed"))
212+
{
213+
await _httpClient.ExecuteAsync(BuildHttpRequest($"/api/v0/transfers/downloads/{downloadItem.Username}/{file.Id}", HttpMethod.Delete));
214+
await Task.Delay(1000);
215+
}
216+
await _httpClient.ExecuteAsync(BuildHttpRequest($"/api/v0/transfers/downloads/{downloadItem.Username}/{file.Id}?remove=true", HttpMethod.Delete));
217+
_logger.Trace($"Removed download with ID {file.Id}.");
218+
}));
214219
}
215220

216221
private async Task<HttpResponse> ExecuteAsync(HttpRequest request) => await _httpClient.ExecuteAsync(request);

Tubifarry/Download/Clients/Soulseek/SlskdModels.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using NzbDrone.Common.Disk;
2-
using NzbDrone.Common.Instrumentation;
32
using NzbDrone.Core.Indexers.Soulseek;
43
using NzbDrone.Core.Parser.Model;
54
using System.Text.Json;
@@ -14,7 +13,7 @@ public class SlskdDownloadItem
1413

1514
public int ID { get; set; }
1615
public List<SlskdFileData> FileData { get; set; } = new();
17-
public string Username { get; set; } = string.Empty;
16+
public string? Username { get; set; }
1817
public RemoteAlbum RemoteAlbum { get; set; }
1918
public SlskdDownloadDirectory? SlskdDownloadDirectory { get; set; }
2019

Tubifarry/Download/Clients/Soulseek/SlskdProviderSettings.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ public SlskdProviderSettingsValidator()
1515
.Must(url => !url.EndsWith("/"))
1616
.WithMessage("Base URL must not end with a slash ('/').");
1717

18-
// External URL validation (only if not empty)
19-
RuleFor(c => c.ExternalUrl)
20-
.Must(url => string.IsNullOrEmpty(url) || (Uri.IsWellFormedUriString(url, UriKind.Absolute) && !url.EndsWith("/")))
21-
.WithMessage("External URL must be a valid URL and must not end with a slash ('/').");
22-
2318
// API Key validation
2419
RuleFor(c => c.ApiKey)
2520
.NotEmpty()
@@ -40,9 +35,6 @@ public class SlskdProviderSettings : IProviderConfig
4035
[FieldDefinition(0, Label = "URL", Type = FieldType.Url, Placeholder = "http://localhost:5030", HelpText = "The URL of your Slskd instance.")]
4136
public string BaseUrl { get; set; } = "http://localhost:5030";
4237

43-
[FieldDefinition(1, Label = "External URL", Type = FieldType.Url, Placeholder = "https://slskd.example.com", HelpText = "An optional external URL for additional resources or documentation.", Advanced = true)]
44-
public string? ExternalUrl { get; set; } = string.Empty;
45-
4638
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, HelpText = "The API key for your Slskd instance. You can find or set this in the Slskd's settings under 'Options'.", Placeholder = "Enter your API key")]
4739
public string ApiKey { get; set; } = string.Empty;
4840

Tubifarry/Indexers/Soulseek/SlskdParser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,16 @@ private AlbumData CreateAlbumData(string searchId, IGrouping<string, SlskdFileDa
9090
bitRate = (int)((totalSize * 8) / (totalDuration * 1000));
9191

9292
List<SlskdFileData>? filesToDownload = directory.GroupBy(f => f.Filename?[..f.Filename.LastIndexOf('\\')]).FirstOrDefault(g => g.Key == directory.Key)?.ToList();
93-
93+
AudioFormat codec = AudioFormatHelper.GetAudioCodecFromExtension(mostCommonExtension ?? string.Empty);
9494
return new AlbumData("Slskd")
9595
{
9696
AlbumId = $"/api/v0/transfers/downloads/{folderData.Username}",
9797
ArtistName = artist ?? "Unknown Artist",
9898
AlbumName = album ?? "Unknown Album",
9999
ReleaseDate = folderData.Year,
100100
ReleaseDateTime = (string.IsNullOrEmpty(folderData.Year) || !int.TryParse(folderData.Year, out int yearInt) ? DateTime.MinValue : new DateTime(yearInt, 1, 1)),
101-
Codec = AudioFormatHelper.GetAudioCodecFromExtension(mostCommonExtension ?? string.Empty),
102-
Bitrate = bitRate ?? 0,
101+
Codec = codec,
102+
Bitrate = (codec == AudioFormat.MP3 ? AudioFormatHelper.RoundToStandardBitrate(bitRate ?? 0) : bitRate) ?? 0,
103103
Size = totalSize,
104104
Priotity = folderData.CalculatePriority(),
105105
CustomString = JsonConvert.SerializeObject(filesToDownload),
@@ -129,7 +129,7 @@ public void RemoveSearch(string searchId, bool delay = false)
129129
{
130130
try
131131
{
132-
if (delay) await Task.Delay(30000);
132+
if (delay) await Task.Delay(90000);
133133
HttpRequest request = new HttpRequestBuilder($"{Settings.BaseUrl}/api/v0/searches/{searchId}").SetHeader("X-API-KEY", Settings.ApiKey).Build();
134134
request.Method = HttpMethod.Delete;
135135
HttpResponse response = await _httpClient.ExecuteAsync(request);

Tubifarry/Indexers/Soulseek/SlskdSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public class SlskdSettings : IIndexerSettings
6868
[FieldDefinition(0, Label = "URL", Type = FieldType.Url, Placeholder = "http://localhost:5030", HelpText = "The URL of your Slskd instance.")]
6969
public string BaseUrl { get; set; } = "http://localhost:5030";
7070

71-
[FieldDefinition(1, Label = "External URL", Type = FieldType.Url, Placeholder = "https://slskd.example.com", HelpText = "An optional external URL for additional resources or documentation.", Advanced = true)]
71+
[FieldDefinition(1, Label = "External URL", Type = FieldType.Url, Placeholder = "https://slskd.example.com", HelpText = "URL for interactive search redirect", Advanced = true)]
7272
public string? ExternalUrl { get; set; } = string.Empty;
7373

7474
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, HelpText = "The API key for your Slskd instance. You can find or set this in the Slskd's settings under 'Options'.", Placeholder = "Enter your API key")]

Tubifarry/Indexers/Spotify/SpotifyToYoutubeParser.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public interface ISpotifyToYoutubeParser : IParseIndexerResponse
2323
public class SpotifyToYoutubeParser : ISpotifyToYoutubeParser
2424
{
2525
private YouTubeMusicClient _ytClient;
26-
private static readonly int[] StandardBitrates = { 96, 128, 160, 192, 256, 320 };
2726

2827
private readonly Logger _logger;
2928
private string? _cookiePath;
@@ -172,7 +171,7 @@ private async Task AddYoutubeData(AlbumData albumData)
172171
if (highestAudioStreamInfo != null)
173172
{
174173
albumData.Duration = (long)album.Duration.TotalSeconds;
175-
albumData.Bitrate = RoundToStandardBitrate(highestAudioStreamInfo.Bitrate / 1000);
174+
albumData.Bitrate = AudioFormatHelper.RoundToStandardBitrate(highestAudioStreamInfo.Bitrate / 1000);
176175
albumData.AlbumId = result.Id;
177176
break;
178177
}
@@ -214,7 +213,5 @@ private static string NormalizeTitle(string title)
214213
}
215214
return title;
216215
}
217-
218-
private static int RoundToStandardBitrate(int bitrateKbps) => StandardBitrates.OrderBy(b => Math.Abs(b - bitrateKbps)).First();
219216
}
220217
}

0 commit comments

Comments
 (0)