Skip to content

Commit

Permalink
Merge pull request #204 from lardbit/video-detection-settings
Browse files Browse the repository at this point in the history
Add settings for fake video detection
  • Loading branch information
lardbit authored Jul 4, 2022
2 parents 4f3d8d3 + 5548798 commit 14d80a0
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 13 deletions.
22 changes: 22 additions & 0 deletions src/frontend/src/app/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,28 @@
<button type="button" class="btn btn-xs btn-sm btn-outline-primary" (click)="sendTestNotification()">Send test notification <span class="oi oi-bolt"></span></button>
</div>
</div>
<!-- video detection -->
<div class="card">
<div class="card-header d-flex justify-content-between">
<span>Video Validation</span>
</div>
<div class="card-body">
<div>Automatically detect, blacklist, and retry <strong>fake</strong> videos.</div>
<div><span class="badge badge-dark">Note</span> This will also reject any bundled downloads (e.g. rar, tar, zip)</div>
<div class="form-check mt-2">
<input class="form-check-input" type="radio" [value]="true" formControlName="enable_video_detection" id="video-detection-true">
<label class="form-check-label" for="video-detection-true">
Enable
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" [value]="false" formControlName="enable_video_detection" id="video-detection-false">
<label class="form-check-label" for="video-detection-false">
Disable
</label>
</div>
</div>
</div>
</div>
<!-- import library -->
<div class="col-12 col-sm-6 col-md-4">
Expand Down
1 change: 1 addition & 0 deletions src/frontend/src/app/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class SettingsComponent implements OnInit, AfterContentChecked {
'quality_profile_tv': [settings['quality_profile_tv'], Validators.required],
'quality_profile_movies': [settings['quality_profile_movies'], Validators.required],
'allow_hardcoded_subs': [settings['allow_hardcoded_subs'], Validators.required],
'enable_video_detection': [settings['enable_video_detection'], Validators.required],
'exclusions': [settings['keyword_search_filters'] ? _.keys(settings['keyword_search_filters']) : []],
'language': [settings['language'], Validators.required],
'users': new FormArray([]),
Expand Down
10 changes: 5 additions & 5 deletions src/nefarious/importer/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def ingest_path(self, file_path):
if file_extension_match:
# skip sample files
if parser.sample_file_regex.search(file_name):
logger_background.warning('[NO_MATCH_SAMPLE] Not matching sample file "{}"'.format(file_path))
logger_background.info('[NO_MATCH_SAMPLE] Not matching sample file "{}"'.format(file_path))
return False
title = parser.match['title']
if not title:
Expand All @@ -66,7 +66,7 @@ def ingest_path(self, file_path):
title = new_title
parser.match.update(parser_match)
else:
logger_background.warning('[NO_MATCH_TITLE] Could not match file without title "{}"'.format(file_path))
logger_background.info('[NO_MATCH_TITLE] Could not match file without title "{}"'.format(file_path))
return False
file_extension = file_extension_match.group()
if file_extension in video_extensions():
Expand All @@ -91,11 +91,11 @@ def ingest_path(self, file_path):
logger_background.info('[MATCH] Saved media "{}" from file "{}"'.format(watch_media, file_path))
return watch_media
else: # for/else
logger_background.warning('[NO_MATCH_MEDIA] No media match for title "{}" and file "{}"'.format(title, file_path))
logger_background.info('[NO_MATCH_MEDIA] No media match for title "{}" and file "{}"'.format(title, file_path))
else:
logger_background.warning('[NO_MATCH_VIDEO] No valid video file extension for file "{}"'.format(file_path))
logger_background.info('[NO_MATCH_VIDEO] No valid video file extension for file "{}"'.format(file_path))
else:
logger_background.warning('[NO_MATCH_EXTENSION] No file extension for file "{}"'.format(file_path))
logger_background.info('[NO_MATCH_EXTENSION] No file extension for file "{}"'.format(file_path))
else:
logger_background.info('[NO_MATCH_UNKNOWN] Unknown match for file "{}"'.format(file_path))
return False
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.0.2 on 2022-07-04 14:09

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('nefarious', '0069_auto_20211128_1337'),
]

operations = [
migrations.AddField(
model_name='nefarioussettings',
name='enable_fake_video_detection',
field=models.BooleanField(default=False),
),
]
22 changes: 22 additions & 0 deletions src/nefarious/migrations/0071_auto_20220704_2043.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 3.0.2 on 2022-07-04 20:43

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('nefarious', '0070_nefarioussettings_enable_fake_video_detection'),
]

operations = [
migrations.RemoveField(
model_name='nefarioussettings',
name='enable_fake_video_detection',
),
migrations.AddField(
model_name='nefarioussettings',
name='enable_video_detection',
field=models.BooleanField(default=True),
),
]
4 changes: 4 additions & 0 deletions src/nefarious/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ class NefariousSettings(models.Model):
quality_profile_tv = models.CharField(max_length=500, default=quality.PROFILE_ANY.name, choices=zip(quality.PROFILE_NAMES, quality.PROFILE_NAMES))
quality_profile_movies = models.CharField(max_length=500, default=quality.PROFILE_HD_720P_1080P.name, choices=zip(quality.PROFILE_NAMES, quality.PROFILE_NAMES))

# whether to allow hardcoded subtitles
allow_hardcoded_subs = models.BooleanField(default=False)

# whether to enable video detection features (e.g. fake)
enable_video_detection = models.BooleanField(default=False)

# expects keyword/boolean pairs like {"x265": false, "265": false}
keyword_search_filters = JSONField(blank=True, null=True) # type: dict

Expand Down
11 changes: 7 additions & 4 deletions src/nefarious/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,21 @@ def completed_media_task():

logger_background.info('Media completed: {}'.format(media))

# run video detection on the relevant video files for movies
if isinstance(media, WatchMovie):
# run video detection, if enabled, on the relevant video files for movies, staging_path
if nefarious_settings.enable_video_detection and isinstance(media, WatchMovie):
logger_background.info("[VIDEO_DETECTION] verifying '{}'".format(media))
staging_path = os.path.join(
settings.INTERNAL_DOWNLOAD_PATH,
settings.UNPROCESSED_PATH,
nefarious_settings.transmission_movie_download_dir.lstrip('/'),
torrent.name,
)
try:
if not VideoDetect.has_valid_video_in_path(staging_path):
if VideoDetect.has_valid_video_in_path(staging_path):
logger_background.info("[VIDEO_DETECTION] '{}' has valid video files".format(media))
else:
blacklist_media_and_retry(media)
logger_background.error("Blacklisting video '{}' because no valid video was found: {}".format(media, staging_path))
logger_background.error("[VIDEO_DETECTION] blacklisting '{}' because no valid video was found: {}".format(media, staging_path))
continue
except Exception as e:
logger_background.exception(e)
Expand Down
7 changes: 3 additions & 4 deletions src/nefarious/video_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def __init__(self, video_path: str):

@classmethod
def has_valid_video_in_path(cls, path: str):
# TODO - remove once fixed bug https://github.com/lardbit/nefarious/issues/203
return True
# TODO - this doesn't handle bundles (rar/zip/tar etc) since it won't find any "media" files

files_to_verify = []

Expand Down Expand Up @@ -65,8 +64,8 @@ def has_valid_video_in_path(cls, path: str):
return True
return False

def is_correct_length(self, correct_duration: float):
return abs(self.duration - correct_duration) / correct_duration < self.MAX_VIDEO_DURATION_DIFFERENCE_RATIO
def is_correct_length(self, expected_duration: float):
return abs(self.duration - expected_duration) / expected_duration < self.MAX_VIDEO_DURATION_DIFFERENCE_RATIO

def is_too_similar(self):
return self.video_similarity_std <= self.MIN_VIDEO_SIMILARITY_STD
Expand Down

0 comments on commit 14d80a0

Please sign in to comment.