Skip to content

Commit 629c302

Browse files
author
Meyn
committed
Cleaned up the Readme and fixed the overly strict YouTube search criteria.
1 parent 6d3a821 commit 629c302

File tree

8 files changed

+221
-81
lines changed

8 files changed

+221
-81
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: Bug Report
3+
about: Create a report to help us improve
4+
title: "[BUG]"
5+
labels: bug
6+
assignees:
7+
---
8+
9+
**Version**
10+
- Tubifarry Version: [e.g., v1.2.0]
11+
- Lidarr Version: [e.g., v1.0.0]
12+
- Operating System: [e.g., Windows 10, Ubuntu 20.04, Docker]
13+
14+
**Describe the Bug**
15+
A clear and concise description of what the bug is.
16+
17+
**Feature Problem**
18+
Explain the specific feature or functionality that is not working as intended.
19+
20+
**To Reproduce**
21+
Steps to reproduce the behavior:
22+
1. Go to '...'
23+
2. Click on '....'
24+
3. Scroll down to '....'
25+
4. See error
26+
27+
**Expected Behavior**
28+
A clear and concise description of what you expected to happen.
29+
30+
**Screenshots**
31+
<details>
32+
<summary>For Pictures click here</summary>
33+
34+
Add screenshots here to help explain your problem.
35+
</details>
36+
37+
**Additional Context**
38+
Add any other context about the problem here.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# .github/ISSUE_TEMPLATE/config.yml
2+
3+
# Disable blank issues (users must use a template)
4+
blank_issues_enabled: false
5+
6+
# Set up contact links for additional support options
7+
contact_links:
8+
- name: 🐛 Bug Reports
9+
url: https://github.com/TypNull/Tubifarry/issues/new?template=bug_report.md
10+
about: Report a bug or unexpected behavior in Tubifarry.
11+
12+
- name: ✨ Feature Requests
13+
url: https://github.com/TypNull/Tubifarry/issues/new?template=feature_request.md
14+
about: Suggest a new feature or improvement for Tubifarry.
15+
16+
- name: ❓ Questions & Support
17+
url: https://github.com/TypNull/Tubifarry/discussions
18+
about: Ask questions or get help with Tubifarry in our Discussions forum.
19+
20+
- name: 📚 Documentation
21+
url: https://github.com/TypNull/Tubifarry/wiki
22+
about: Check out the official documentation for Tubifarry.
23+
24+
# Optional: Customize the order of templates (if you have multiple templates)
25+
# templates:
26+
# - feature_request.md
27+
# - bug_report.md
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
name: Feature Request
3+
about: Suggest an idea or improvement for Tubifarry
4+
title: "[FEATURE]"
5+
labels: enhancement
6+
assignees:
7+
---
8+
9+
**Is your feature request related to a problem? Please describe.**
10+
A clear and concise description of what the problem is. For example:
11+
- "I’m always frustrated when..."
12+
- "Currently, it’s difficult to..."
13+
14+
**Describe the Solution You'd Like**
15+
A clear and concise description of what you want to happen. Include any specific functionality or changes you’d like to see.
16+
17+
**Describe Alternatives You've Considered**
18+
A clear and concise description of any alternative solutions or features you've considered. This helps us understand your thought process and explore other options.
19+
20+
**Additional Context**
21+
Add any other context, screenshots, or examples about the feature request here. For example:
22+
- Why this feature would be valuable.
23+
- How it aligns with the goals of Tubifarry.
24+
- Any technical considerations or constraints.
25+
26+
<details>
27+
<summary>For Screenshots or Mockups, click here</summary>
28+
29+
Add any relevant screenshots, diagrams, or mockups to illustrate your idea.
30+
</details>
31+
32+
---
33+
34+
**Technical Details (Optional)**
35+
If you have technical expertise or ideas for implementation, feel free to share:
36+
- Proposed architecture or design.
37+
- APIs or libraries that could be used.
38+
- Any potential challenges or risks.
39+
40+
---
41+
42+
**Contributions Welcome!**
43+
If you’re interested in contributing to this feature, let us know! We’re happy to guide you through the process.
44+
45+
---
46+
47+
**Thank You!**
48+
We appreciate your feedback and ideas. Your input helps make Tubifarry better for everyone! 🎉

README.md

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ Additionally, Tubifarry supports fetching soundtracks from **Sonarr** (series) a
99

1010
## Table of Contents 📑
1111

12-
1. [Tubifarry for Lidarr 🎶](#tubifarry-for-lidarr-)
13-
2. [Installation 🚀](#installation-)
14-
3. [Soulseek (Slskd) Setup 🎧](#soulseek-slskd-setup-)
15-
4. [YouTube Downloader Setup 🎥](#youtube-downloader-setup-)
16-
5. [Fetching Soundtracks 🎬🎵](#fetching-soundtracks-from-sonarr-and-radarr-)
17-
6. [Queue Cleaner 🧹](#queue-cleaner-)
18-
7. [Troubleshooting 🛠️](#troubleshooting-)
12+
1. [Installation 🚀](#installation-)
13+
2. [Soulseek (Slskd) Setup 🎧](#soulseek-slskd-setup-)
14+
3. [YouTube Downloader Setup 🎥](#youtube-downloader-setup-)
15+
4. [Fetching Soundtracks 🎬🎵](#fetching-soundtracks-from-sonarr-and-radarr-)
16+
5. [Queue Cleaner 🧹](#queue-cleaner-)
17+
6. [Troubleshooting 🛠️](#troubleshooting-%EF%B8%8F)
1918

2019
----
2120

@@ -64,6 +63,10 @@ Tubifarry supports **Slskd**, the Soulseek client, as both an **indexer** and **
6463
### YouTube Downloader Setup 🎥
6564
Tubifarry allows you to download music directly from YouTube. Follow the steps below to configure the YouTube downloader.
6665

66+
#### **Configure the Indexer**:
67+
1. Navigate to `Settings -> Indexers` and click **Add**.
68+
2. In the modal, select `Tubifarry` (located under **Other** at the bottom).
69+
6770
#### **Setting Up the YouTube Download Client**:
6871
1. Go to `Settings -> Download Clients` and click **Add**.
6972
2. Select `Youtube` from the list of download clients.
@@ -82,9 +85,6 @@ Tubifarry allows you to download music directly from YouTube. Follow the steps b
8285

8386
**Note**: For higher-quality audio (e.g., 256kb/s), you need a **YouTube Premium subscription**.
8487

85-
3. **Saving .lrc Files**:
86-
If you want to save **.lrc files** (lyric files), navigate to **Media Management > Advanced Settings > Import Extra Files** and add `lrc` to the list of supported file types. This ensures that lyric files are imported and saved alongside your music files.
87-
8888
---
8989

9090
### Fetching Soundtracks from Sonarr and Radarr 🎬🎵
@@ -120,18 +120,28 @@ The **Queue Cleaner** automatically processes items in your Lidarr queue that ha
120120
---
121121

122122
## Troubleshooting 🛠️
123-
- **Slskd Download Path Permissions**: Ensure Lidarr has read/write access to the Slskd download path. Verify folder permissions and ensure the user running Lidarr has the necessary access. For Docker setups, confirm the volume is correctly mounted and permissions are set.
124-
- **Optional: FFmpeg Issues**: If you choose to use FFmpeg and songs fail to process, verify that FFmpeg is correctly installed and accessible in your system's PATH. If not, try reinstalling or downloading it manually.
125-
- **Metadata Issues**: If metadata is not being added to downloaded files, confirm that the files are in a supported format. If using FFmpeg, ensure it is extracting audio to formats like AAC embedded in MP4 containers (check debug logs).
126-
- **No Release Found**: If no release is found, YouTube might flag the plugin as a bot (which it technically is). To avoid this and access higher-quality audio, you can log in using cookies.
127-
- **Steps to Use Cookies**:
128-
1. Install the **cookies.txt** extension for your browser:
129-
- [Get cookies.txt for Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
130-
- [Get cookies.txt for Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
131-
2. Log in to YouTube and save the cookies.txt file in a folder accessible by Lidarr.
132-
3. Go to the **Indexer and Downloader** settings in Lidarr and add the file path to the cookies.txt file.
133123

134-
---
124+
- **Slskd Download Path Permissions**:
125+
Ensure Lidarr has read/write access to the Slskd download path. Verify folder permissions and confirm the user running Lidarr has the necessary access. For Docker setups, double-check that the volume is correctly mounted and permissions are properly configured.
126+
127+
- **FFmpeg Issues (Optional)**:
128+
If you’re using FFmpeg and songs fail to process, ensure FFmpeg is installed correctly and accessible in your system’s PATH. If issues persist, try reinstalling FFmpeg or downloading it manually.
129+
130+
- **Metadata Issues**:
131+
If metadata isn’t being added to downloaded files, confirm the files are in a supported format. If using FFmpeg, check that it’s extracting audio to compatible formats like AAC embedded in MP4 containers. Review debug logs for further details.
132+
133+
- **No Release Found**:
134+
If no release is found, YouTube may flag the plugin as a bot. To avoid this and access higher-quality audio, log in using cookies:
135+
1. Install the **cookies.txt** extension for your browser:
136+
- [Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
137+
- [Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
138+
2. Log in to YouTube and save the `cookies.txt` file in a folder accessible by Lidarr.
139+
3. In Lidarr, go to **Indexer and Downloader Settings** and provide the path to the `cookies.txt` file.
140+
141+
- **No Lyrics Imported**:
142+
To save `.lrc` files (lyric files), navigate to **Media Management > Advanced Settings > Import Extra Files** and add `lrc` to the list of supported file types. This ensures lyric files are imported and saved alongside your music files.
143+
144+
---
135145

136146
## Acknowledgments 🙌
137147
Special thanks to [**trevTV**](https://github.com/TrevTV) for laying the groundwork with his plugins. Additionally, thanks to [**IcySnex**](https://github.com/IcySnex) for providing the YouTube API. 🎉

Tubifarry/Core/FileCache.cs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Text.Json;
1+
using FluentValidation.Results;
2+
using NLog;
3+
using System.Text.Json;
24

35
namespace Tubifarry.Core
46
{
@@ -68,5 +70,74 @@ private class CachedData<T>
6870
public DateTime CreatedAt { get; set; }
6971
public TimeSpan ExpirationDuration { get; set; }
7072
}
73+
74+
public static ValidationFailure? TestPermissions(string directoryPath, ILogger logger)
75+
{
76+
if (string.IsNullOrWhiteSpace(directoryPath))
77+
{
78+
logger.Warn("Directory path is null or empty.");
79+
return new ValidationFailure("DirectoryPath", "Directory path cannot be null or empty.");
80+
}
81+
82+
try
83+
{
84+
if (!Directory.Exists(directoryPath))
85+
Directory.CreateDirectory(directoryPath);
86+
87+
string testFilePath = Path.Combine(directoryPath, "test_permissions.tmp");
88+
89+
try
90+
{
91+
File.WriteAllText(testFilePath, "This is a test file to check write permissions.");
92+
}
93+
catch (UnauthorizedAccessException ex)
94+
{
95+
logger.Warn(ex, "Write permission denied for directory");
96+
return new ValidationFailure("DirectoryPath", $"Write permission denied for directory: {ex.Message}");
97+
}
98+
99+
try
100+
{
101+
string content = File.ReadAllText(testFilePath);
102+
}
103+
catch (UnauthorizedAccessException ex)
104+
{
105+
logger.Warn(ex, "Read permission denied for directory");
106+
return new ValidationFailure("DirectoryPath", $"Read permission denied for directory: {ex.Message}");
107+
}
108+
109+
try
110+
{
111+
string[] files = Directory.GetFiles(directoryPath);
112+
}
113+
catch (UnauthorizedAccessException ex)
114+
{
115+
logger.Warn(ex, "Execute permission denied for directory");
116+
return new ValidationFailure("DirectoryPath", $"Execute permission denied for directory: {ex.Message}");
117+
}
118+
119+
try
120+
{
121+
File.Delete(testFilePath);
122+
}
123+
catch (UnauthorizedAccessException ex)
124+
{
125+
logger.Warn(ex, "Delete permission denied for directory");
126+
return new ValidationFailure("DirectoryPath", $"Delete permission denied for directory: {ex.Message}");
127+
}
128+
129+
return null;
130+
}
131+
catch (IOException ex)
132+
{
133+
logger.Warn(ex, "IO error while testing directory permissions");
134+
return new ValidationFailure("DirectoryPath", $"IO error while testing directory: {ex.Message}");
135+
}
136+
catch (Exception ex)
137+
{
138+
logger.Error(ex, "Unexpected error while testing directory permissions");
139+
return new ValidationFailure("DirectoryPath", $"Unexpected error: {ex.Message}");
140+
}
141+
}
71142
}
72143
}

Tubifarry/Download/Clients/YouTube/YoutubeClient.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ public async Task<ValidationFailure> TestFFmpeg()
6767
return new ValidationFailure("FFmpegInstallation", $"Failed to install FFmpeg: {ex.Message}");
6868
}
6969
}
70+
71+
if (Settings.DownloadPath != null)
72+
return FileCache.TestPermissions(Settings.FFmpegPath, _logger)!;
7073
}
7174
return null!;
7275
}

Tubifarry/ImportLists/ArrStack/ArrSoundtrackImport.cs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using NzbDrone.Core.Parser;
77
using NzbDrone.Core.ThingiProvider;
88
using System.Net;
9+
using Tubifarry.Core;
910

1011
namespace NzbDrone.Core.ImportLists.ArrStack
1112
{
@@ -37,7 +38,7 @@ public ArrSoundtrackImport(IHttpClient httpClient, IImportListStatusService impo
3738
protected override void Test(List<ValidationFailure> failures)
3839
{
3940
failures!.AddIfNotNull(TestConnection());
40-
failures!.AddIfNotNull(TestWritePermission());
41+
failures!.AddIfNotNull(FileCache.TestPermissions(Settings.CacheDirectory, _logger));
4142
}
4243

4344
private new ValidationFailure? TestConnection()
@@ -70,35 +71,6 @@ protected override void Test(List<ValidationFailure> failures)
7071
}
7172
}
7273

73-
private ValidationFailure? TestWritePermission()
74-
{
75-
try
76-
{
77-
if (!Directory.Exists(Settings.CacheDirectory))
78-
Directory.CreateDirectory(Settings.CacheDirectory);
79-
string testFilePath = Path.Combine(Settings.CacheDirectory, "test_write_permission.tmp");
80-
File.WriteAllText(testFilePath, "This is a test file to check write permissions.");
81-
string content = File.ReadAllText(testFilePath);
82-
File.Delete(testFilePath);
83-
return null;
84-
}
85-
catch (UnauthorizedAccessException ex)
86-
{
87-
_logger.Warn(ex, "Write permission denied for cache directory");
88-
return new ValidationFailure("CacheDirectory", $"Write permission denied for cache directory: {ex.Message}");
89-
}
90-
catch (IOException ex)
91-
{
92-
_logger.Warn(ex, "IO error while testing cache directory write permissions");
93-
return new ValidationFailure("CacheDirectory", $"IO error while testing cache directory: {ex.Message}");
94-
}
95-
catch (Exception ex)
96-
{
97-
_logger.Error(ex, "Unexpected error while testing cache directory write permissions");
98-
return new ValidationFailure("CacheDirectory", $"Unexpected error: {ex.Message}");
99-
}
100-
}
101-
10274
public override IEnumerable<ProviderDefinition> DefaultDefinitions
10375
{
10476
get

Tubifarry/Indexers/Spotify/SpotifyToYoutubeParser.cs

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using Requests;
55
using Requests.Options;
66
using System.Text.Json;
7-
using System.Text.RegularExpressions;
87
using Tubifarry.Core;
98
using YouTubeMusicAPI.Client;
109
using YouTubeMusicAPI.Models.Search;
@@ -147,8 +146,6 @@ private async Task AddYoutubeData(AlbumData albumData)
147146
if (result == null)
148147
continue;
149148

150-
if (!IsRelevantResult(result, albumData)) continue;
151-
152149
string browsID = await _ytClient.GetAlbumBrowseIdAsync(result.Id);
153150
YouTubeMusicAPI.Models.Info.AlbumInfo album = await _ytClient.GetAlbumInfoAsync(browsID);
154151

@@ -186,31 +183,5 @@ private async Task AddYoutubeData(AlbumData albumData)
186183
_logger.Error($"Error while adding Youtube data: {ex.Message}");
187184
}
188185
}
189-
190-
private static bool IsRelevantResult(AlbumSearchResult result, AlbumData parameters)
191-
{
192-
string normalizedResultName = NormalizeTitle(result.Name);
193-
string normalizedParametersAlbumName = NormalizeTitle(parameters.AlbumName);
194-
195-
bool isAlbumMatch = normalizedResultName.Contains(normalizedParametersAlbumName, StringComparison.OrdinalIgnoreCase);
196-
bool isArtistMatch = result.Artists.Any(x => x.Name.Contains(parameters.ArtistName, StringComparison.OrdinalIgnoreCase));
197-
198-
return isAlbumMatch && isArtistMatch;
199-
}
200-
201-
private static string NormalizeTitle(string title)
202-
{
203-
title = Regex.Replace(title, @"[\(\[].*?[\)\]]", "").Trim();
204-
title = Regex.Replace(title, @"\[\w+(_\w+)?\]", "").Trim();
205-
Match match = Regex.Match(title, @"^(?<artist>.+?)(?: - )(?<album>.+?)(?: - )(?<year>\d{4})");
206-
if (match.Success)
207-
{
208-
string artist = match.Groups["artist"].Value.Trim();
209-
string album = match.Groups["album"].Value.Trim();
210-
string year = match.Groups["year"].Value.Trim();
211-
title = $"{artist} - {album} - {year}";
212-
}
213-
return title;
214-
}
215186
}
216187
}

0 commit comments

Comments
 (0)