From 2800c4ee834bebdd607a37cca6fbe1f40835d89b Mon Sep 17 00:00:00 2001
From: Ruud <ruud@crashdummy.nl>
Date: Fri, 28 Dec 2012 17:40:17 +0100
Subject: [PATCH] 3D quality profile support

---
 couchpotato/core/plugins/profile/main.py      | 13 +++++-
 .../core/plugins/profile/static/profile.css   | 43 +++++++++++++++--
 .../core/plugins/profile/static/profile.js    | 46 +++++++++++++++----
 couchpotato/core/plugins/quality/main.py      |  7 +--
 couchpotato/core/plugins/scanner/main.py      |  2 +-
 5 files changed, 91 insertions(+), 20 deletions(-)

diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py
index 4caa54f7..18c54f1d 100644
--- a/couchpotato/core/plugins/profile/main.py
+++ b/couchpotato/core/plugins/profile/main.py
@@ -3,6 +3,7 @@ from couchpotato.api import addApiView
 from couchpotato.core.event import addEvent, fireEvent
 from couchpotato.core.helpers.encoding import toUnicode
 from couchpotato.core.helpers.request import jsonified, getParams, getParam
+from couchpotato.core.helpers.variable import tryInt
 from couchpotato.core.logger import CPLog
 from couchpotato.core.plugins.base import Plugin
 from couchpotato.core.settings.model import Profile, ProfileType
@@ -71,7 +72,8 @@ class ProfilePlugin(Plugin):
         for type in params.get('types', []):
             t = ProfileType(
                 order = order,
-                finish = type.get('finish') if order > 0 else 1,
+                finish = tryInt(type.get('finish')) if order > 0 else 1,
+                threed = tryInt(type.get('3d')),
                 wait_for = params.get('wait_for'),
                 quality_id = type.get('quality_id')
             )
@@ -151,6 +153,9 @@ class ProfilePlugin(Plugin):
         }, {
             'label': 'SD',
             'qualities': ['dvdrip', 'dvdr']
+        }, {
+            'label': 'Prefer 3D HD',
+            'qualities': [('720p', True), ('1080p', True), '720p', '1080p']
         }]
 
         # Create default quality profile
@@ -165,11 +170,17 @@ class ProfilePlugin(Plugin):
 
             quality_order = 0
             for quality in profile.get('qualities'):
+
+                threed = False
+                if isinstance(quality, (tuple, list)):
+                    quality, threed = quality
+
                 quality = fireEvent('quality.single', identifier = quality, single = True)
                 profile_type = ProfileType(
                     quality_id = quality.get('id'),
                     profile = p,
                     finish = True,
+                    threed = threed,
                     wait_for = 0,
                     order = quality_order
                 )
diff --git a/couchpotato/core/plugins/profile/static/profile.css b/couchpotato/core/plugins/profile/static/profile.css
index 9d50d2fd..926e8d12 100644
--- a/couchpotato/core/plugins/profile/static/profile.css
+++ b/couchpotato/core/plugins/profile/static/profile.css
@@ -12,7 +12,7 @@
 		height: 20px;
 		width: 20px;
 		position: absolute;
-		margin-left: 690px;
+		margin: 8px 0 0 690px;
 		padding: 14px;
 		background-position: center;
 	}
@@ -22,7 +22,7 @@
 	}
 
 	.profile .formHint {
-		width: 250px !important;
+		width: 210px !important;
 		vertical-align: top !important;
 		margin: 0 !important;
 		padding-left: 3px !important;
@@ -62,22 +62,52 @@
 			}
 
 			.profile .quality_type select {
-				width: 186px;
+				width: 120px;
 				margin-left: -1px;
 			}
 
-			.profile .types li.is_empty .check, .profile .types li.is_empty .delete, .profile .types li.is_empty .handle {
+			.profile .types li.is_empty .check, 
+			.profile .types li.is_empty .delete, 
+			.profile .types li.is_empty .handle, 
+			.profile .types li.is_empty .check_label {
 				visibility: hidden;
 			}
+			
+			.profile .types .type label {
+				display: inline-block;
+				width: auto;
+				float: none;
+				text-transform: uppercase;
+				font-size: 11px;
+				font-weight: normal;
+				margin-right: 20px;
+				text-shadow: none;
+				vertical-align: top;
+			}
+				.profile .types .type label .check {
+					margin-right: 5px;
+				}
+				.profile .types .type label .check_label {
+					padding: 2px 0;
+					display: inline-block;
+				}
+				
+				.profile .types .type .threed {
+					display: none;
+				}
+				
+				.profile .types .type.allow_3d .threed {
+					display: inline-block;
+				}
 
 		.profile .types .type .handle {
 			background: url('./handle.png') center;
 			display: inline-block;
 			height: 20px;
 			width: 20px;
-			cursor: grab;
 			cursor: -moz-grab;
 			cursor: -webkit-grab;
+			cursor: grab;
 			margin: 0;
 		}
 
@@ -88,6 +118,9 @@
 			visibility: hidden;
 			cursor: pointer;
 		}
+		.profile .types .type:not(.allow_3d) .delete {
+			margin-left: 55px;
+		}
 
 		.profile .types .type:hover:not(.is_empty) .delete {
 			visibility: visible;
diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js
index 3bb44989..e16a35ca 100644
--- a/couchpotato/core/plugins/profile/static/profile.js
+++ b/couchpotato/core/plugins/profile/static/profile.js
@@ -49,7 +49,7 @@ var Profile = new Class({
 				new Element('label', {'text': 'Search for'}),
 				self.type_container = new Element('ol.types'),
 				new Element('div.formHint', {
-					'html': "Search these qualities (2 minimum), from top to bottom. Use the checkbox, to stop searching after it found this quality."
+					'html': "Search these qualities (2 minimum), from top to bottom."
 				})
 			)
 		);
@@ -87,7 +87,7 @@ var Profile = new Class({
 				'onComplete': function(json){
 					if(json.success){
 						self.data = json.profile;
-						self.type_container.getElement('li:first-child input[type=checkbox]')
+						self.type_container.getElement('li:first-child input[type=checkbox].finish')
 							.set('checked', true)
 							.getParent().addClass('checked');
 					}
@@ -112,7 +112,8 @@ var Profile = new Class({
 			if(!type.hasClass('deleted') && type.getElement('select').get('value') > 0)
 				data.types.include({
 					'quality_id': type.getElement('select').get('value'),
-					'finish': +type.getElement('input[type=checkbox]').checked
+					'finish': +type.getElement('input[type=checkbox].finish').checked,
+					'3d': +type.getElement('input[type=checkbox].3d').checked
 				});
 		})
 
@@ -226,8 +227,11 @@ Profile.Type = new Class({
 		self.create();
 
 		self.addEvent('change', function(){
-			self.el[self.qualities.get('value') == '-1' ? 'addClass' : 'removeClass']('is_empty');
-			self.deleted = self.qualities.get('value') == '-1';
+			var qu = self.qualities.get('value');
+			self.el[qu == '-1' ? 'addClass' : 'removeClass']('is_empty');
+			self.el[Quality.getQuality(qu).allow_3d ? 'addClass': 'removeClass']('allow_3d');
+
+			self.deleted = qu == '-1';
 		});
 
 	},
@@ -240,11 +244,13 @@ Profile.Type = new Class({
 			new Element('span.quality_type').adopt(
 				self.fillQualities()
 			),
-			new Element('span.finish').adopt(
+			self.finish_container = new Element('label.finish').adopt(
 				self.finish = new Element('input.inlay.finish[type=checkbox]', {
 					'checked': data.finish !== undefined ? data.finish : 1,
 					'events': {
 						'change': function(e){
+							self['3d_container'].addClass('enabled');
+
 							if(self.el == self.el.getParent().getElement(':first-child')){
 								self.finish_class.check();
 								alert('Top quality always finishes the search')
@@ -254,7 +260,21 @@ Profile.Type = new Class({
 							self.fireEvent('change');
 						}
 					}
-				})
+				}),
+				new Element('span.check_label[text=finish]')
+			),
+			self['3d_container'] = new Element('label.threed').adopt(
+				self['3d'] = new Element('input.inlay.3d[type=checkbox]', {
+					'checked': data['threed'] !== undefined ? data['threed'] : 0,
+					'events': {
+						'change': function(e){
+							self['3d_container'].addClass('enabled');
+
+							self.fireEvent('change');
+						}
+					}
+				}),
+				new Element('span.check_label[text=3D]')
 			),
 			new Element('span.delete.icon', {
 				'events': {
@@ -266,7 +286,11 @@ Profile.Type = new Class({
 
 		self.el[self.data.quality_id > 0 ? 'removeClass' : 'addClass']('is_empty');
 
+		if(self.data.quality_id > 0 && Quality.getQuality(self.data.quality_id).allow_3d)
+			self.el.addClass('allow_3d');
+
 		self.finish_class = new Form.Check(self.finish);
+		self['3d_class'] = new Form.Check(self['3d']);
 
 	},
 
@@ -279,7 +303,7 @@ Profile.Type = new Class({
 			}
 		}).adopt(
 			new Element('option', {
-				'text': '+ Add another quality',
+				'text': '+ Add quality',
 				'value': -1
 			})
 		);
@@ -287,7 +311,8 @@ Profile.Type = new Class({
 		Object.each(Quality.qualities, function(q){
 			new Element('option', {
 				'text': q.label,
-				'value': q.id
+				'value': q.id,
+				'data-allow_3d': q.allow_3d
 			}).inject(self.qualities)
 		});
 
@@ -302,7 +327,8 @@ Profile.Type = new Class({
 
 		return {
 			'quality_id': self.qualities.get('value'),
-			'finish': +self.finish.checked
+			'finish': +self.finish.checked,
+			'3d': +self['3d'].checked
 		}
 	},
 
diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py
index aeb74e58..7a867e1e 100644
--- a/couchpotato/core/plugins/quality/main.py
+++ b/couchpotato/core/plugins/quality/main.py
@@ -18,9 +18,9 @@ log = CPLog(__name__)
 class QualityPlugin(Plugin):
 
     qualities = [
-        {'identifier': 'bd50', 'hd': True, 'size': (15000, 60000), 'label': 'BR-Disk', 'alternative': ['bd25'], 'allow': ['1080p'], 'ext':[], 'tags': ['bdmv', 'certificate', ('complete', 'bluray')]},
-        {'identifier': '1080p', 'hd': True, 'size': (5000, 20000), 'label': '1080P', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts'], 'tags': ['m2ts']},
-        {'identifier': '720p', 'hd': True, 'size': (3500, 10000), 'label': '720P', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'ts']},
+        {'identifier': 'bd50', 'allow_3d': True, 'hd': True, 'size': (15000, 60000), 'label': 'BR-Disk', 'alternative': ['bd25'], 'allow': ['1080p'], 'ext':[], 'tags': ['bdmv', 'certificate', ('complete', 'bluray')]},
+        {'identifier': '1080p', 'allow_3d': True, 'hd': True, 'size': (5000, 20000), 'label': '1080P', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts'], 'tags': ['m2ts']},
+        {'identifier': '720p', 'allow_3d': True, 'hd': True, 'size': (3500, 10000), 'label': '720P', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'ts']},
         {'identifier': 'brrip', 'hd': True, 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip'], 'allow': ['720p'], 'ext':['avi']},
         {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': [], 'allow': [], 'ext':['iso', 'img'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts']},
         {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': ['dvdrip'], 'allow': [], 'ext':['avi', 'mpg', 'mpeg'], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]},
@@ -31,6 +31,7 @@ class QualityPlugin(Plugin):
         {'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': [], 'ext':['avi', 'mpg', 'mpeg']}
     ]
     pre_releases = ['cam', 'ts', 'tc', 'r5', 'scr']
+    tags_3d = ['3d', 'hsbs', ('half', 'sbs'), ('full', 'sbs')]
 
     def __init__(self):
         addEvent('quality.all', self.all)
diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py
index 2a1d3078..84b4bc07 100644
--- a/couchpotato/core/plugins/scanner/main.py
+++ b/couchpotato/core/plugins/scanner/main.py
@@ -74,7 +74,7 @@ class Scanner(Plugin):
         'hdtv': ['hdtv']
     }
 
-    clean = '[ _\,\.\(\)\[\]\-](french|swedisch|danish|dutch|swesub|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|video_ts|audio_ts|480p|480i|576p|576i|720p|720i|1080p|1080i|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|cd[1-9]|\[.*\])([ _\,\.\(\)\[\]\-]|$)'
+    clean = '[ _\,\.\(\)\[\]\-](3d|hsbs|sbs|french|swedisch|danish|dutch|swesub|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|video_ts|audio_ts|480p|480i|576p|576i|720p|720i|1080p|1080i|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|cd[1-9]|\[.*\])([ _\,\.\(\)\[\]\-]|$)'
     multipart_regex = [
         '[ _\.-]+cd[ _\.-]*([0-9a-d]+)', #*cd1
         '[ _\.-]+dvd[ _\.-]*([0-9a-d]+)', #*dvd1
-- 
GitLab