Repository: pymedusa/Medusa

Issue:
Files don't have subfolders! SHOWQUEUE-REFRESH tries to clean a files subfolders
### Before submitting your issue:

Enable debug logging in Medusa settings, reproduce the error (be sure to disable after the bug is fixed)

**Branch/Commit:** Dev ee778e94195098ec9d602703ba0dcbb0b3db8192
**OS:** Win 10; Python 2.7.13
**What you did:**  Observed SHOWQUEUE-REFRESH logs
**What happened:**  Logs showed multiple attempts to clear a file's subdirectories.  Files don't have subdirectories.
**What you expected:**  Single attempt for the folder, and not trying subdirectories of a file.
**Logs:**
```
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\banner.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\clearart.png
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\clearlogo.png
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\fanart.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\logo.png
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season-all-banner.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season-all-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1969-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1985-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1988-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1990-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1991-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1992-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1993-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1994-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1995-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1996-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1997-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1998-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season1999-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2000-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2001-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2002-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2003-poster.jpg
2017-01-25 23:57:28 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2004-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2005-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2006-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2007-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2008-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2009-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2010-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2011-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2012-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2013-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2014-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2015-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2016-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\season2017-poster.jpg
2017-01-25 23:57:29 INFO     SHOWQUEUE-REFRESH :: [ee778e9] Trying to clean any empty folders under D:\- Series\BBC Documentaries\tvshow.nfo
```



Discussion:

Resolving patch:
diff --git a/medusa/helpers.py b/medusa/helpers.py
--- a/medusa/helpers.py
+++ b/medusa/helpers.py
@@ -185,6 +185,7 @@ def make_dir(path):
     if not os.path.isdir(path):
         try:
             os.makedirs(path)
+
             # do the library update for synoindex
             from . import notifiers
             notifiers.synoindex_notifier.addFolder(path)
@@ -435,6 +436,7 @@ def make_dirs(path):
                     os.mkdir(sofar)
                     # use normpath to remove end separator, otherwise checks permissions against itself
                     chmod_as_parent(os.path.normpath(sofar))
+
                     # do the library update for synoindex
                     from . import notifiers
                     notifiers.synoindex_notifier.addFolder(sofar)
@@ -497,39 +499,37 @@ def rename_ep_file(cur_path, new_path, old_path_length=0):
     return True
 
 
-def delete_empty_folders(check_empty_dir, keep_dir=None):
+def delete_empty_folders(top_dir, keep_dir=None):
     """Walk backwards up the path and deletes any empty folders found.
 
-    :param check_empty_dir: The path to clean (absolute path to a folder)
-    :type check_empty_dir: str
-    :param keep_dir: Clean until this path is reached
+    :param top_dir: Clean until this directory is reached (absolute path to a folder)
+    :type top_dir: str
+    :param keep_dir: Don't delete this directory, even if it's empty
     :type keep_dir: str
     """
-    # treat check_empty_dir as empty when it only contains these items
-    ignore_items = []
+    if not top_dir or not os.path.isdir(top_dir):
+        return
 
-    logger.info(u'Trying to clean any empty folders under {path}', path=check_empty_dir)
+    logger.info(u'Trying to clean any empty folder under {path}'.format(path=top_dir))
 
-    # as long as the folder exists and doesn't contain any files, delete it
-    while os.path.isdir(check_empty_dir) and check_empty_dir != keep_dir:
-        check_files = os.listdir(check_empty_dir)
+    for directory in os.walk(top_dir, topdown=False):
+        dirpath = directory[0]
 
-        if not check_files or (len(check_files) <= len(ignore_items) and all(
-                [check_file in ignore_items for check_file in check_files])):
-            # directory is empty or contains only ignore_items
+        if dirpath == top_dir:
+            return
+
+        if dirpath != keep_dir and not os.listdir(dirpath):
             try:
-                logger.info(u'Deleting empty folder: {folder}', folder=check_empty_dir)
-                # need shutil.rmtree when ignore_items is really implemented
-                os.rmdir(check_empty_dir)
-                # do the library update for synoindex
+                logger.info(u'Deleting empty folder: {folder}'.format(folder=dirpath))
+                os.rmdir(dirpath)
+
+                # Do the library update for synoindex
                 from . import notifiers
-                notifiers.synoindex_notifier.deleteFolder(check_empty_dir)
+                notifiers.synoindex_notifier.deleteFolder(dirpath)
             except OSError as e:
-                logger.warning(u'Unable to delete {folder}. Error: {error!r}', folder=check_empty_dir, error=e)
-                break
-            check_empty_dir = os.path.dirname(check_empty_dir)
+                logger.warning(u'Unable to delete {folder}. Error: {error!r}'.format(folder=dirpath, error=e))
         else:
-            break
+            logger.debug(u'Not deleting {folder}. The folder is not empty or should be kept.'.format(folder=dirpath))
 
 
 def file_bit_filter(mode):
diff --git a/medusa/notifiers/boxcar2.py b/medusa/notifiers/boxcar2.py
--- a/medusa/notifiers/boxcar2.py
+++ b/medusa/notifiers/boxcar2.py
@@ -18,23 +18,28 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with Medusa. If not, see <http://www.gnu.org/licenses/>.
-
+"""Boxcar2 module."""
 from __future__ import unicode_literals
 
-from .. import app, common, helpers, logger
+from .. import app, common, logger
+from ..helpers import get_url, make_session
 
 
 class Notifier(object):
+    """Boxcar2 class."""
+
     def __init__(self):
-        self.session = helpers.make_session()
+        """Initialize the class."""
+        self.session = make_session()
         self.url = 'https://new.boxcar.io/api/notifications'
 
     def test_notify(self, accesstoken, title='Medusa: Test'):
-        return self._sendBoxcar2('This is a test notification from Medusa', title, accesstoken)
+        """Test the notify."""
+        return self._send_boxcar2('This is a test notification from Medusa', title, accesstoken)
 
-    def _sendBoxcar2(self, msg, title, accesstoken):
+    def _send_boxcar2(self, msg, title, accesstoken):
         """
-        Sends a boxcar2 notification to the address provided
+        Send a boxcar2 notification to the address provided.
 
         msg: The message to send
         title: The title of the message
@@ -53,7 +58,7 @@ def _sendBoxcar2(self, msg, title, accesstoken):
             'notification[icon_url]': app.LOGO_URL
         }
 
-        response = helpers.get_url(self.url, post_data=post_data, session=self.session, timeout=60, returns='json')
+        response = get_url(self.url, post_data=post_data, session=self.session, timeout=60, returns='json')
         if not response:
             logger.log('Boxcar2 notification failed.', logger.ERROR)
             return False
@@ -62,37 +67,41 @@ def _sendBoxcar2(self, msg, title, accesstoken):
         return True
 
     def notify_snatch(self, ep_name, is_proper):
-        title=common.notifyStrings[(common.NOTIFY_SNATCH, common.NOTIFY_SNATCH_PROPER)[is_proper]]
+        """Send the snatch message."""
+        title = common.notifyStrings[(common.NOTIFY_SNATCH, common.NOTIFY_SNATCH_PROPER)[is_proper]]
         if app.BOXCAR2_NOTIFY_ONSNATCH:
-            self._notifyBoxcar2(title, ep_name)
+            self._notify_boxcar2(title, ep_name)
 
     def notify_download(self, ep_name, title=common.notifyStrings[common.NOTIFY_DOWNLOAD]):
+        """Send the download message."""
         if app.BOXCAR2_NOTIFY_ONDOWNLOAD:
-            self._notifyBoxcar2(title, ep_name)
+            self._notify_boxcar2(title, ep_name)
 
     def notify_subtitle_download(self, ep_name, lang, title=common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD]):
+        """Send the subtitle download message."""
         if app.BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD:
-            self._notifyBoxcar2(title, ep_name + ': ' + lang)
+            self._notify_boxcar2(title, ep_name + ': ' + lang)
 
     def notify_git_update(self, new_version='??'):
+        """Send update available message."""
         update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT]
         title = common.notifyStrings[common.NOTIFY_GIT_UPDATE]
-        self._notifyBoxcar2(title, update_text + new_version)
+        self._notify_boxcar2(title, update_text + new_version)
 
     def notify_login(self, ipaddress=''):
+        """Send the new login message."""
         update_text = common.notifyStrings[common.NOTIFY_LOGIN_TEXT]
         title = common.notifyStrings[common.NOTIFY_LOGIN]
-        self._notifyBoxcar2(title, update_text.format(ipaddress))
+        self._notify_boxcar2(title, update_text.format(ipaddress))
 
-    def _notifyBoxcar2(self, title, message, accesstoken=None):
+    def _notify_boxcar2(self, title, message, accesstoken=None):
         """
-        Sends a boxcar2 notification based on the provided info or SB config
+        Send a boxcar2 notification based on the provided info or SB config.
 
         title: The title of the notification to send
         message: The message string to send
         accesstoken: to send to this device
         """
-
         if not app.USE_BOXCAR2:
             logger.log('Notification for Boxcar2 not enabled, skipping this notification', logger.DEBUG)
             return False
@@ -101,4 +110,4 @@ def _notifyBoxcar2(self, title, message, accesstoken=None):
 
         logger.log('Sending notification for {}'.format(message), logger.DEBUG)
 
-        return self._sendBoxcar2(message, title, accesstoken)
+        return self._send_boxcar2(message, title, accesstoken)
diff --git a/medusa/tv.py b/medusa/tv.py
--- a/medusa/tv.py
+++ b/medusa/tv.py
@@ -1549,10 +1549,8 @@ def refresh_dir(self):
                                     u'{id}: Could not delete associated file: {related_file}. Error: {error_msg}'.format
                                     (id=self.indexerid, related_file=related_file, error_msg=e), logger.WARNING)
 
-        # clean up any empty season folders after deletion of associated files
-        if os.path.isdir(self.location):
-            for sub_dir in os.listdir(self.location):
-                helpers.delete_empty_folders(os.path.join(self.location, sub_dir), self.location)
+        # Clean up any empty season folders after deletion of associated files
+        helpers.delete_empty_folders(self.location)
 
         if sql_l:
             main_db_con = db.DBConnection()


Test patch: