Repository: pymedusa/Medusa

Issue:
[APP SUBMITTED]: ValueError: (u'String does not contain a date:', u'Yesterday at\xa0Today at\xa0')

### INFO
**Python Version**: `2.7.9 (default, Sep 17 2016, 20:26:04) [GCC 4.9.2]`
**Operating System**: `Linux-4.9.35-v7+-armv7l-with-debian-8.0`
**Locale**: `UTF-8`
**Branch**: [develop](../tree/develop)
**Database**: `44.12`
**Commit**: pymedusa/Medusa@d7da5942b5307d5ca1e982d7073155a84699751a
**Link to Log**: https://gist.github.com/9c18c5ffe1b56fa442c4d75e693ac514
### ERROR
<pre>
2018-09-01 09:52:46 ERROR    SEARCHQUEUE-DAILY-SEARCH :: [HDSpace] :: [d7da594] Failed parsing publishing date: Yesterday at Today at 
Traceback (most recent call last):
  File "/home/pi/Medusa/<a href="../blob/d7da5942b5307d5ca1e982d7073155a84699751a/medusa/providers/generic_provider.py#L582">medusa/providers/generic_provider.py</a>", line 582, in parse_pubdate
    dt = parser.parse(pubdate, dayfirst=df, yearfirst=yf, fuzzy=True)
  File "/home/pi/Medusa/<a href="../blob/d7da5942b5307d5ca1e982d7073155a84699751a/ext/dateutil/parser/_parser.py#L1356">ext/dateutil/parser/_parser.py</a>", line 1356, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/home/pi/Medusa/<a href="../blob/d7da5942b5307d5ca1e982d7073155a84699751a/ext/dateutil/parser/_parser.py#L651">ext/dateutil/parser/_parser.py</a>", line 651, in parse
    raise ValueError("String does not contain a date:", timestr)
ValueError: (u'String does not contain a date:', u'Yesterday at\xa0Today at\xa0')
</pre>
---
_STAFF NOTIFIED_: @pymedusa/support @pymedusa/moderators



Discussion:
Lol what kind of date is yesterday at today? 
It seems more that the parsing joined 2 dates:

![image](https://pls.gtfo.accountant/9GSC8.png)

Cab you provide the source for that? 
Yes, sent via slack.
```
<td align="center" width="85" class="lista" style="white-space:wrap; text-align:center;"><b>Yesterday</b> at&nbsp;22:11:02&nbsp;</td>
```


I did some research, and the only lib that supports strings like `yesterday at 14:02:01` or `today at 12:02:09` is dateparser. We don't have this currently added. So or we write the logic as a helper specifically for this provider. Or we add dateparser? @medariox thoughts?

Resolving patch:
diff --git a/medusa/providers/generic_provider.py b/medusa/providers/generic_provider.py
--- a/medusa/providers/generic_provider.py
+++ b/medusa/providers/generic_provider.py
@@ -574,12 +574,25 @@ def parse_pubdate(pubdate, human_time=False, timezone=None, **kwargs):
                         matched_time = int(round(float(matched_time.strip())))
 
                     seconds = parse('{0} {1}'.format(matched_time, matched_granularity))
+                    if seconds is None:
+                        log.warning('Failed parsing human time: {0} {1}', matched_time, matched_granularity)
+                        raise ValueError('Failed parsing human time: {0} {1}'.format(matched_time, matched_granularity))
+
                 return datetime.now(tz.tzlocal()) - timedelta(seconds=seconds)
 
             if fromtimestamp:
                 dt = datetime.fromtimestamp(int(pubdate), tz=tz.gettz('UTC'))
             else:
-                dt = parser.parse(pubdate, dayfirst=df, yearfirst=yf, fuzzy=True)
+                day_offset = 0
+                if 'yesterday at' in pubdate.lower() or 'today at' in pubdate.lower():
+                    # Extract a time
+                    time = re.search(r'(?P<time>[0-9:]+)', pubdate)
+                    if time:
+                        if 'yesterday' in pubdate:
+                            day_offset = 1
+                        pubdate = time.group('time').strip()
+
+                dt = parser.parse(pubdate, dayfirst=df, yearfirst=yf, fuzzy=True) - timedelta(days=day_offset)
 
             # Always make UTC aware if naive
             if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None:
diff --git a/medusa/providers/torrent/html/hdspace.py b/medusa/providers/torrent/html/hdspace.py
--- a/medusa/providers/torrent/html/hdspace.py
+++ b/medusa/providers/torrent/html/hdspace.py
@@ -155,7 +155,14 @@ def parse(self, data, mode):
                     torrent_size = row.find('td', class_='lista222', attrs={'width': '100%'}).get_text()
                     size = convert_size(torrent_size) or -1
 
-                    pubdate_raw = row.find_all('td', class_='lista', attrs={'align': 'center'})[3].get_text()
+                    pubdate_td = row.find_all('td', class_='lista', attrs={'align': 'center'})[3]
+                    pubdate_human_offset = pubdate_td.find('b')
+                    if pubdate_human_offset:
+                        time_search = re.search('([0-9:]+)', pubdate_td.get_text())
+                        pubdate_raw = pubdate_human_offset.get_text() + ' at ' + time_search.group(1)
+                    else:
+                        pubdate_raw = pubdate_td.get_text()
+
                     pubdate = self.parse_pubdate(pubdate_raw)
 
                     item = {


Test patch:
diff --git a/tests/providers/test_generic_provider.py b/tests/providers/test_generic_provider.py
--- a/tests/providers/test_generic_provider.py
+++ b/tests/providers/test_generic_provider.py
@@ -2,7 +2,7 @@
 """Provider test code for Generic Provider."""
 from __future__ import unicode_literals
 
-from datetime import date, datetime
+from datetime import date, datetime, timedelta
 
 from dateutil import tz
 
@@ -127,6 +127,16 @@
         'timezone': 'US/Eastern',
         'fromtimestamp': True
     },
+    {  # p22: hd-space test human date like 'yesterday at 12:00:00'
+        'pubdate': 'yesterday at {0}'.format((datetime.now() - timedelta(minutes=10, seconds=25)).strftime('%H:%M:%S')),
+        'expected': datetime.now().replace(microsecond=0, tzinfo=tz.gettz('UTC')) - timedelta(days=1, minutes=10, seconds=25),
+        'human_time': False
+    },
+    {  # p23: hd-space test human date like 'today at 12:00:00'
+        'pubdate': 'today at {0}'.format((datetime.now() - timedelta(minutes=10, seconds=25)).strftime('%H:%M:%S')),
+        'expected': datetime.now().replace(microsecond=0, tzinfo=tz.gettz('UTC')) - timedelta(days=0, minutes=10, seconds=25),
+        'human_time': False
+    },
 ])
 def test_parse_pubdate(p):
     # Given