Skip to content

Commit

Permalink
Adds #538
Browse files Browse the repository at this point in the history
  • Loading branch information
bobokun committed May 1, 2024
1 parent d5aaa31 commit 797fe27
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 7 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.1.3-develop6
4.1.3-develop7
4 changes: 4 additions & 0 deletions config/config.yml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,16 @@ nohardlinks:
- Beyond-HD
- AnimeBytes
- MaM
# <OPTIONAL> ignore_root_dir var: Will ignore any hardlinks detected in the same root_dir (Default True).
ignore_root_dir: true
# Can have additional categories set with separate ratio/seeding times defined.
- series-completed:
# <OPTIONAL> exclude_tags var: Will exclude torrents with any of the following tags when searching through the category.
exclude_tags:
- Beyond-HD
- BroadcasTheNet
# <OPTIONAL> ignore_root_dir var: Will ignore any hardlinks detected in the same root_dir (Default True).
ignore_root_dir: true

share_limits:
# Control how torrent share limits are set depending on the priority of your grouping
Expand Down
1 change: 1 addition & 0 deletions docs/Config-Setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Beyond this you'll need to use one of the [categories](#cat) above as the key, a
| Variable | Definition | Default Values | Required |
| :------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :----------------- |
| `exclude_tags` | List of tags to exclude from the check. Torrents with any of these tags will not be processed. This is useful to exclude certain trackers from being scanned for hardlinking purposes | None | <center>❌</center> |
| `ignore_root_dir` | Ignore any hardlinks detected in the same [root_dir](#directory) | True | <center>❌</center> |

## **share_limits:**

Expand Down
6 changes: 6 additions & 0 deletions modules/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,15 @@ def hooks(attr):
if isinstance(exclude_tags, str):
exclude_tags = [exclude_tags]
self.nohardlinks[cat_str]["exclude_tags"] = exclude_tags
self.nohardlinks[cat_str]["ignore_root_dir"] = cat[cat_str].get("ignore_root_dir", True)
if not isinstance(self.nohardlinks[cat_str]["ignore_root_dir"], bool):
err = f"Config Error: nohardlinks category {cat_str} attribute ignore_root_dir must be a boolean type"
self.notify(err, "Config")
raise Failed(err)
elif isinstance(cat, str):
self.nohardlinks[cat] = {}
self.nohardlinks[cat]["exclude_tags"] = []
self.nohardlinks[cat]["ignore_root_dir"] = True
else:
if self.commands["tag_nohardlinks"]:
err = "Config Error: nohardlinks must be a list of categories"
Expand Down
4 changes: 3 additions & 1 deletion modules/core/tag_nohardlinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ def tag_nohardlinks(self):
for torrent in torrent_list:
tracker = self.qbt.get_tags(self.qbt.get_tracker_urls(torrent.trackers))
has_nohardlinks = check_hardlinks.nohardlink(
torrent["content_path"].replace(self.root_dir, self.remote_dir), self.config.notify
torrent["content_path"].replace(self.root_dir, self.remote_dir),
self.config.notify,
nohardlinks[category]["ignore_root_dir"],
)
if any(util.is_tag_in_torrent(tag, torrent.tags) for tag in nohardlinks[category]["exclude_tags"]):
# Skip to the next torrent if we find any torrents that are in the exclude tag
Expand Down
15 changes: 10 additions & 5 deletions modules/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,14 +479,21 @@ def get_inode_count(self):
else:
self.inode_count[inode_no] = 1

def nohardlink(self, file, notify):
def nohardlink(self, file, notify, ignore_root_dir):
"""
Check if there are any hard links
Will check if there are any hard links if it passes a file or folder
If a folder is passed, it will take the largest file in that folder and only check for hardlinks
of the remaining files where the file is greater size a percentage of the largest file
This fixes the bug in #192
"""

def check_hardlinks(self, file, ignore_root_dir):
if ignore_root_dir:
return os.stat(file).st_nlink - self.inode_count.get(os.stat(file).st_ino, 1) > 0
else:
return os.stat(file).st_nlink > 1

check_for_hl = True
try:
if os.path.isfile(file):
Expand All @@ -498,7 +505,7 @@ def nohardlink(self, file, notify):
logger.trace(f"Checking no of hard links: {os.stat(file).st_nlink}")
logger.trace(f"Checking inode_count dict: {self.inode_count.get(os.stat(file).st_ino)}")
# https://github.com/StuffAnThings/qbit_manage/issues/291 for more details
if os.stat(file).st_nlink - self.inode_count.get(os.stat(file).st_ino, 1) > 0:
if check_hardlinks(self, file, ignore_root_dir):
check_for_hl = False
else:
sorted_files = sorted(Path(file).rglob("*"), key=lambda x: os.stat(x).st_size, reverse=True)
Expand Down Expand Up @@ -527,9 +534,7 @@ def nohardlink(self, file, notify):
logger.trace(f"Checking file size: {file_size}")
logger.trace(f"Checking no of hard links: {file_no_hardlinks}")
logger.trace(f"Checking inode_count dict: {self.inode_count.get(os.stat(files).st_ino)}")
if file_no_hardlinks - self.inode_count.get(os.stat(files).st_ino, 1) > 0 and file_size >= (
largest_file_size * threshold
):
if check_hardlinks(self, files, ignore_root_dir) and file_size >= (largest_file_size * threshold):
check_for_hl = False
except PermissionError as perm:
logger.warning(f"{perm} : file {file} has permission issues. Skipping...")
Expand Down

0 comments on commit 797fe27

Please sign in to comment.