diff --git a/Pipfile b/Pipfile
index 54f76614974856e795efce82b3af3548cf08b83c..000f3f81810891a2b41407646fe3786d8221f64c 100644
--- a/Pipfile
+++ b/Pipfile
@@ -3,12 +3,18 @@ url = "https://pypi.python.org/simple"
 verify_ssl = true
 name = "pypi"
 
+[[source]]
+url = "https://pypi.thecodedev.de"
+verify_ssl = true
+name = "TheCodeLabs"
+
 [requires]
 python_version = "3.7"
 
 [packages]
 google-api-python-client = "==1.8"
 youtube_dl = "==2020.3.24"
+TheCodeLabs-BaseUtils = "==1.0.0"
 
 [dev-packages]
 pyinstaller = "==3.5"
\ No newline at end of file
diff --git a/Pipfile.lock b/Pipfile.lock
index b09c42e695ee7f0a0ce44e416abc031367d9547a..869f7628b3e8f6ce50e5ff500c0e1d5a07457f5c 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "fff7d0afede620fb0976a0d7a968e2ebbbc277b07d67b8fbb4b9734a6772285b"
+            "sha256": "ae4bf9210af7e87ca2f1eb4cd6f79f9887d6a1c1d4198f7c9e48ae2da938f749"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -12,23 +12,28 @@
                 "name": "pypi",
                 "url": "https://pypi.python.org/simple",
                 "verify_ssl": true
+            },
+            {
+                "name": "TheCodeLabs",
+                "url": "https://pypi.thecodedev.de",
+                "verify_ssl": true
             }
         ]
     },
     "default": {
         "cachetools": {
             "hashes": [
-                "sha256:9a52dd97a85f257f4e4127f15818e71a0c7899f121b34591fcc1173ea79a0198",
-                "sha256:b304586d357c43221856be51d73387f93e2a961598a9b6b6670664746f3b6c6c"
+                "sha256:1d057645db16ca7fe1f3bd953558897603d6f0b9c51ed9d11eb4d071ec4e2aab",
+                "sha256:de5d88f87781602201cde465d3afe837546663b168e8b39df67411b0bf10cefc"
             ],
-            "version": "==4.0.0"
+            "version": "==4.1.0"
         },
         "certifi": {
             "hashes": [
-                "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3",
-                "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"
+                "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304",
+                "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"
             ],
-            "version": "==2019.11.28"
+            "version": "==2020.4.5.1"
         },
         "chardet": {
             "hashes": [
@@ -39,10 +44,10 @@
         },
         "google-api-core": {
             "hashes": [
-                "sha256:859f7392676761f2b160c6ee030c3422135ada4458f0948c5690a6a7c8d86294",
-                "sha256:92e962a087f1c4b8d1c5c88ade1c1dfd550047dcffb320c57ef6a534a20403e2"
+                "sha256:c0e430658ed6be902d7ba7095fb0a9cac810270d71bf7ac4484e76c300407aae",
+                "sha256:e4082a0b479dc2dee2f8d7b80ea8b5d0184885b773caab15ab1836277a01d689"
             ],
-            "version": "==1.16.0"
+            "version": "==1.17.0"
         },
         "google-api-python-client": {
             "hashes": [
@@ -54,10 +59,10 @@
         },
         "google-auth": {
             "hashes": [
-                "sha256:a5ee4c40fef77ea756cf2f1c0adcf475ecb53af6700cf9c133354cdc9b267148",
-                "sha256:cab6c707e6ee20e567e348168a5c69dc6480384f777a9e5159f4299ad177dcc0"
+                "sha256:0c41a453b9a8e77975bfa436b8daedac00aed1c545d84410daff8272fff40fbb",
+                "sha256:e63b2210e03c4ed829063b72c4af0c4b867c2788efb3210b6b9439b488bd3afd"
             ],
-            "version": "==1.13.1"
+            "version": "==1.14.1"
         },
         "google-auth-httplib2": {
             "hashes": [
@@ -74,10 +79,10 @@
         },
         "httplib2": {
             "hashes": [
-                "sha256:4e26d60a6b37ff0e8401e976f13667cb3746dfa1b50833003b7f138042b54247",
-                "sha256:b81b2cd2248285168a4359f2acf24521a4099b5853e790309c45dcb90ee4b3c6"
+                "sha256:39dd15a333f67bfb70798faa9de8a6e99c819da6ad82b77f9a259a5c7b1225a2",
+                "sha256:6d9722decd2deacd486ef10c5dd5e2f120ca3ba8736842b90509afcdc16488b1"
             ],
-            "version": "==0.17.1"
+            "version": "==0.17.3"
         },
         "idna": {
             "hashes": [
@@ -125,10 +130,10 @@
         },
         "pytz": {
             "hashes": [
-                "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
-                "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
+                "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed",
+                "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"
             ],
-            "version": "==2019.3"
+            "version": "==2020.1"
         },
         "requests": {
             "hashes": [
@@ -151,6 +156,13 @@
             ],
             "version": "==1.14.0"
         },
+        "thecodelabs-baseutils": {
+            "hashes": [
+                "sha256:cd1033b8a7110a6ef31a638e87554dba5c901c3da43d7a1b98162c3aa00ae8cf"
+            ],
+            "index": "pypi",
+            "version": "==1.0.0"
+        },
         "uritemplate": {
             "hashes": [
                 "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f",
@@ -160,10 +172,10 @@
         },
         "urllib3": {
             "hashes": [
-                "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
-                "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
+                "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527",
+                "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"
             ],
-            "version": "==1.25.8"
+            "version": "==1.25.9"
         },
         "youtube-dl": {
             "hashes": [
diff --git a/SaveMyPlaylist.py b/SaveMyPlaylist.py
index 40c64ece1a592a62b271deb8a053a7f1ba4dadac..876107d5f3edc1c87d32178c8cf090765eaa6002 100644
--- a/SaveMyPlaylist.py
+++ b/SaveMyPlaylist.py
@@ -1,38 +1,16 @@
 from __future__ import unicode_literals
 
 import json
-import logging
 import os
 import sys
 
 import googleapiclient.discovery
 import googleapiclient.errors
 import youtube_dl
+from TheCodeLabs_BaseUtils import DefaultLogger
 
-
-def prepare_logging() -> logging.Logger:
-    LOG_FORMAT = '[%(levelname)-7s] - %(asctime)s - %(message)s'
-    DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
-
-    LOG_FORMATTER = logging.Formatter(fmt=LOG_FORMAT, datefmt=DATE_FORMAT)
-
-    logger = logging.getLogger('SaveMyPlaylist')
-    logger.setLevel(logging.DEBUG)
-
-    outHandler = logging.StreamHandler(sys.stdout)
-    outHandler.setFormatter(LOG_FORMATTER)
-    outHandler.setLevel(logging.DEBUG)
-    outHandler.addFilter(lambda record: record.levelno <= logging.INFO)
-    logger.addHandler(outHandler)
-
-    errHandler = logging.StreamHandler(sys.stderr)
-    errHandler.setFormatter(LOG_FORMATTER)
-    errHandler.setLevel(logging.WARNING)
-    logger.addHandler(errHandler)
-    return logger
-
-
-logger = prepare_logging()
+LOG_FORMAT = '[%(levelname)-7s] - %(asctime)s - %(message)s'
+LOGGER = DefaultLogger().create_logger_if_not_exists('SaveMyPlaylist')
 
 
 class MyLogger(object):
@@ -48,7 +26,7 @@ class MyLogger(object):
 
 def my_hook(d):
     if d['status'] == 'finished':
-        logger.info('Download finished for {}'.format(d['filename']))
+        LOGGER.info('Download finished for {}'.format(d['filename']))
 
 
 class SaveMyPlaylist:
@@ -66,8 +44,8 @@ class SaveMyPlaylist:
         with open('version.json', 'r', encoding='utf-8') as f:
             VERSION = json.load(f)['version']
 
-        logger.info('### SaveMyPlaylist {} ###'.format(VERSION['name']))
-        logger.info('=============================')
+        LOGGER.info('### SaveMyPlaylist {} ###'.format(VERSION['name']))
+        LOGGER.info('=============================')
         self._apiKey = apiKey
         self._playlistId = playlistId
         self._youtubeApi = googleapiclient.discovery.build(self.API_NAME, self.API_VERSION, developerKey=self._apiKey)
@@ -81,7 +59,7 @@ class SaveMyPlaylist:
             pageItems, nextPageToken = self.__fetch_playlist_items(nextPageToken)
             items.extend(pageItems)
 
-        logger.info('>>> Found {} items in playlist'.format(len(items)))
+        LOGGER.info('>>> Found {} items in playlist'.format(len(items)))
         return items
 
     def __fetch_playlist_items(self, nextPageToken=None):
@@ -109,7 +87,7 @@ class SaveMyPlaylist:
             channelName = self.__get_channel_name(videoId)
 
             items.append((channelName, title, videoId))
-            logger.info(f'{channelName} - {title} (videoId: {videoId})')
+            LOGGER.info(f'{channelName} - {title} (videoId: {videoId})')
 
         nextPageToken = None
         if 'nextPageToken' in response:
@@ -132,23 +110,23 @@ class SaveMyPlaylist:
 
     def download_items(self, destinationFolder, debug=False):
         os.makedirs(destinationFolder, exist_ok=True)
-        logger.info('>>> Scanning destination folder...')
+        LOGGER.info('>>> Scanning destination folder...')
         downloadedVideos = [f for f in os.listdir(destinationFolder) if
                             os.path.isfile(os.path.join(destinationFolder, f)) and f.endswith('.mp4')]
 
-        logger.info('>>> Found {} videos in destination folder'.format(len(downloadedVideos)))
+        LOGGER.info('>>> Found {} videos in destination folder'.format(len(downloadedVideos)))
 
-        logger.info('>>> Started Downloading...')
+        LOGGER.info('>>> Started Downloading...')
         newVideos = []
         for idx, item in enumerate(self._items):
             fileName = '{} - {}.mp4'.format(item[self.TITLE], item[self.CHANNEL])
             fileName = self.__escape_file_name(fileName)
             if fileName in downloadedVideos:
-                logger.info('Skipping {}/{}: "{}" as it already exists'.format(idx + 1, len(self._items), fileName))
+                LOGGER.info('Skipping {}/{}: "{}" as it already exists'.format(idx + 1, len(self._items), fileName))
                 continue
 
             try:
-                logger.info('Downloading {}/{}: "{}"'.format(idx + 1, len(self._items), fileName))
+                LOGGER.info('Downloading {}/{}: "{}"'.format(idx + 1, len(self._items), fileName))
 
                 ydl_opts = {
                     'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]',
@@ -166,10 +144,10 @@ class SaveMyPlaylist:
 
                 newVideos.append(item)
             except Exception as e:
-                logger.error(f'Error while downloading video "{fileName}" with ID: "{item[self.VIDEO_ID]}"', exc_info=e)
+                LOGGER.error(f'Error while downloading video "{fileName}" with ID: "{item[self.VIDEO_ID]}"', exc_info=e)
 
-        logger.info('>>> Finished Downloading')
-        logger.info('Downloaded {} new videos'.format(len(newVideos)))
+        LOGGER.info('>>> Finished Downloading')
+        LOGGER.info('Downloaded {} new videos'.format(len(newVideos)))
 
     def __escape_file_name(self, fileName):
         for char in self.ILLEGAL_CHARS:
@@ -178,7 +156,7 @@ class SaveMyPlaylist:
         try:
             fileName = fileName.encode('ascii', 'ignore').decode('ascii')
         except Exception as e:
-            logger.error(f'Error while converting filenem "{fileName}" to ascii', exc_info=e)
+            LOGGER.error(f'Error while converting filenem "{fileName}" to ascii', exc_info=e)
 
         return fileName
 
diff --git a/version.json b/version.json
index 44c0bf120fe6d1800d66c18bd14a550e75d45e35..9d4f380decb3a7543b9424a86965bb7c1241ad59 100644
--- a/version.json
+++ b/version.json
@@ -1,7 +1,7 @@
 {
     "version": {
-        "name": "v2.3.1",
-        "code": 9,
-        "date": "18.04.20"
+        "name": "v2.4.0",
+        "code": 10,
+        "date": "02.05.20"
     }
 }
\ No newline at end of file