Skip to content

Commit

Permalink
Cleaned up the Readme and fixed the overly strict YouTube search crit…
Browse files Browse the repository at this point in the history
…eria.
  • Loading branch information
Meyn committed Jan 13, 2025
1 parent 6d3a821 commit debb90e
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 81 deletions.
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: Bug Report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees:
---

**Version**
- Tubifarry Version: [e.g., v1.2.0]
- Lidarr Version: [e.g., v1.0.0]
- Operating System: [e.g., Windows 10, Ubuntu 20.04, Docker]

**Describe the Bug**
A clear and concise description of what the bug is.

**Feature Problem**
Explain the specific feature or functionality that is not working as intended.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected Behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
<details>
<summary>For Pictures click here</summary>

Add screenshots here to help explain your problem.
</details>

**Additional Context**
Add any other context about the problem here.
27 changes: 27 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# .github/ISSUE_TEMPLATE/config.yml

# Disable blank issues (users must use a template)
blank_issues_enabled: false

# Set up contact links for additional support options
contact_links:
- name: 🐛 Bug Reports
url: https://github.com/TypNull/Tubifarry/issues/new?template=bug_report.md
about: Report a bug or unexpected behavior in Tubifarry.

- name: ✨ Feature Requests
url: https://github.com/TypNull/Tubifarry/issues/new?template=feature_request.md
about: Suggest a new feature or improvement for Tubifarry.

- name: ❓ Questions & Support
url: https://github.com/TypNull/Tubifarry/discussions
about: Ask questions or get help with Tubifarry in our Discussions forum.

- name: 📚 Documentation
url: https://github.com/TypNull/Tubifarry/wiki
about: Check out the official documentation for Tubifarry.

# Optional: Customize the order of templates (if you have multiple templates)
# templates:
# - feature_request.md
# - bug_report.md
48 changes: 48 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
name: Feature Request
about: Suggest an idea or improvement for Tubifarry
title: "[FEATURE]"
labels: enhancement
assignees:
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. For example:
- "I’m always frustrated when..."
- "Currently, it’s difficult to..."

**Describe the Solution You'd Like**
A clear and concise description of what you want to happen. Include any specific functionality or changes you’d like to see.

**Describe Alternatives You've Considered**
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.

**Additional Context**
Add any other context, screenshots, or examples about the feature request here. For example:
- Why this feature would be valuable.
- How it aligns with the goals of Tubifarry.
- Any technical considerations or constraints.

<details>
<summary>For Screenshots or Mockups, click here</summary>

Add any relevant screenshots, diagrams, or mockups to illustrate your idea.
</details>

---

**Technical Details (Optional)**
If you have technical expertise or ideas for implementation, feel free to share:
- Proposed architecture or design.
- APIs or libraries that could be used.
- Any potential challenges or risks.

---

**Contributions Welcome!**
If you’re interested in contributing to this feature, let us know! We’re happy to guide you through the process.

---

**Thank You!**
We appreciate your feedback and ideas. Your input helps make Tubifarry better for everyone! 🎉
52 changes: 31 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ Additionally, Tubifarry supports fetching soundtracks from **Sonarr** (series) a

## Table of Contents 📑

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

----

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

#### **Configure the Indexer**:
1. Navigate to `Settings -> Indexers` and click **Add**.
2. In the modal, select `Tubifarry` (located under **Other** at the bottom).

#### **Setting Up the YouTube Download Client**:
1. Go to `Settings -> Download Clients` and click **Add**.
2. Select `Youtube` from the list of download clients.
Expand All @@ -82,9 +85,6 @@ Tubifarry allows you to download music directly from YouTube. Follow the steps b

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

3. **Saving .lrc Files**:
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.

---

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

## Troubleshooting 🛠️
- **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.
- **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.
- **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).
- **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.
- **Steps to Use Cookies**:
1. Install the **cookies.txt** extension for your browser:
- [Get cookies.txt for Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
- [Get cookies.txt for Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
2. Log in to YouTube and save the cookies.txt file in a folder accessible by Lidarr.
3. Go to the **Indexer and Downloader** settings in Lidarr and add the file path to the cookies.txt file.

---
- **Slskd Download Path Permissions**:
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.

- **FFmpeg Issues (Optional)**:
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.

- **Metadata Issues**:
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.

- **No Release Found**:
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:
1. Install the **cookies.txt** extension for your browser:
- [Chrome](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
- [Firefox](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
2. Log in to YouTube and save the `cookies.txt` file in a folder accessible by Lidarr.
3. In Lidarr, go to **Indexer and Downloader Settings** and provide the path to the `cookies.txt` file.

- **No Lyrics Imported**:
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.

---

## Acknowledgments 🙌
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. 🎉
Expand Down
73 changes: 72 additions & 1 deletion Tubifarry/Core/FileCache.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text.Json;
using FluentValidation.Results;
using NLog;
using System.Text.Json;

namespace Tubifarry.Core
{
Expand Down Expand Up @@ -68,5 +70,74 @@ private class CachedData<T>
public DateTime CreatedAt { get; set; }
public TimeSpan ExpirationDuration { get; set; }
}

public static ValidationFailure? TestPermissions(string directoryPath, ILogger logger)
{
if (string.IsNullOrWhiteSpace(directoryPath))
{
logger.Warn("Directory path is null or empty.");
return new ValidationFailure("DirectoryPath", "Directory path cannot be null or empty.");
}

try
{
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);

string testFilePath = Path.Combine(directoryPath, "test_permissions.tmp");

try
{
File.WriteAllText(testFilePath, "This is a test file to check write permissions.");
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "Write permission denied for directory");
return new ValidationFailure("DirectoryPath", $"Write permission denied for directory: {ex.Message}");
}

try
{
string content = File.ReadAllText(testFilePath);
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "Read permission denied for directory");
return new ValidationFailure("DirectoryPath", $"Read permission denied for directory: {ex.Message}");
}

try
{
string[] files = Directory.GetFiles(directoryPath);
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "Execute permission denied for directory");
return new ValidationFailure("DirectoryPath", $"Execute permission denied for directory: {ex.Message}");
}

try
{
File.Delete(testFilePath);
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "Delete permission denied for directory");
return new ValidationFailure("DirectoryPath", $"Delete permission denied for directory: {ex.Message}");
}

return null;
}
catch (IOException ex)
{
logger.Warn(ex, "IO error while testing directory permissions");
return new ValidationFailure("DirectoryPath", $"IO error while testing directory: {ex.Message}");
}
catch (Exception ex)
{
logger.Error(ex, "Unexpected error while testing directory permissions");
return new ValidationFailure("DirectoryPath", $"Unexpected error: {ex.Message}");
}
}
}
}
5 changes: 5 additions & 0 deletions Tubifarry/Download/Clients/YouTube/YoutubeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Download.Clients.YouTube;
using Tubifarry.Core;
using Xabe.FFmpeg;

namespace NzbDrone.Core.Download.Clients.YouTube
{
Expand Down Expand Up @@ -56,6 +57,7 @@ public async Task<ValidationFailure> TestFFmpeg()
{
if (Settings.ReEncode != (int)ReEncodeOptions.Disabled)
{
FFmpeg.SetExecutablesPath(Settings.FFmpegPath);
if (!AudioMetadataHandler.FFmpegIsInstalled)
{
try
Expand All @@ -67,6 +69,9 @@ public async Task<ValidationFailure> TestFFmpeg()
return new ValidationFailure("FFmpegInstallation", $"Failed to install FFmpeg: {ex.Message}");
}
}

if (Settings.DownloadPath != null)
return FileCache.TestPermissions(Settings.FFmpegPath, _logger)!;
}
return null!;
}
Expand Down
32 changes: 2 additions & 30 deletions Tubifarry/ImportLists/ArrStack/ArrSoundtrackImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using NzbDrone.Core.Parser;
using NzbDrone.Core.ThingiProvider;
using System.Net;
using Tubifarry.Core;

namespace NzbDrone.Core.ImportLists.ArrStack
{
Expand Down Expand Up @@ -37,7 +38,7 @@ public ArrSoundtrackImport(IHttpClient httpClient, IImportListStatusService impo
protected override void Test(List<ValidationFailure> failures)
{
failures!.AddIfNotNull(TestConnection());
failures!.AddIfNotNull(TestWritePermission());
failures!.AddIfNotNull(FileCache.TestPermissions(Settings.CacheDirectory, _logger));
}

private new ValidationFailure? TestConnection()
Expand Down Expand Up @@ -70,35 +71,6 @@ protected override void Test(List<ValidationFailure> failures)
}
}

private ValidationFailure? TestWritePermission()
{
try
{
if (!Directory.Exists(Settings.CacheDirectory))
Directory.CreateDirectory(Settings.CacheDirectory);
string testFilePath = Path.Combine(Settings.CacheDirectory, "test_write_permission.tmp");
File.WriteAllText(testFilePath, "This is a test file to check write permissions.");
string content = File.ReadAllText(testFilePath);
File.Delete(testFilePath);
return null;
}
catch (UnauthorizedAccessException ex)
{
_logger.Warn(ex, "Write permission denied for cache directory");
return new ValidationFailure("CacheDirectory", $"Write permission denied for cache directory: {ex.Message}");
}
catch (IOException ex)
{
_logger.Warn(ex, "IO error while testing cache directory write permissions");
return new ValidationFailure("CacheDirectory", $"IO error while testing cache directory: {ex.Message}");
}
catch (Exception ex)
{
_logger.Error(ex, "Unexpected error while testing cache directory write permissions");
return new ValidationFailure("CacheDirectory", $"Unexpected error: {ex.Message}");
}
}

public override IEnumerable<ProviderDefinition> DefaultDefinitions
{
get
Expand Down
Loading

0 comments on commit debb90e

Please sign in to comment.