diff --git a/Dockerfile b/Dockerfile
index cf5a6275eb4ef2798212039c0995ddd1759d54f6..399ec89666a0abad6c18f7a53dcde1ab17ba8f92 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -49,6 +49,9 @@ ENV BBB_SHOW_CHAT false
 ENV BBB_ENABLE_CHAT false
 ENV BBB_REDIS_HOST redis
 ENV BBB_REDIS_CHANNEL chat
+RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata
+ENV TZ Europe/Vienna
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
 
 COPY stream.py ./
 COPY chat.py ./
diff --git a/README.md b/README.md
index 136b96db7459b2254e6e2eec97e3c916fefb5b5d..3d774ba55a229915b68f47e093268c74c53b1ab2 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ You need to set some environment variables to run the container.
 * BBB_URL - URL to BBB including http/https e.g. https://your_BigBlueButton_server/bigbluebutton/api
 * BBB_MEETING_ID - ID of the BBB Meeting (You can get the ID via an API call: https://your_bbb_server/bigbluebutton/api/getMeetings?checksum=<checksum>)
 * BBB_SECRET - Secret of your BBB installation (You can get the secret with: bbb-conf --secret)
-* BBB_STREAM_URL - Stream URL to your streaming server including rtmp. (e.g. rtmp://media_server_url/stream/stream_key)
+* BBB_STREAM_URL - URL of your streaming server including rtmp. Leave out to disable streaming. (e.g. rtmp://media_server_url/stream/stream_key)
 
 #### Optional settings
 * BBB_AS_MODERATOR - if set to "true" the meeting will be joined as moderator
@@ -26,8 +26,13 @@ You need to set some environment variables to run the container.
 * BBB_ATTENDEE_PASSWORD - attendee password (optional - has to be set to the attendee password of moodle/greenlight or any other frontend to allow joining via their links)
 * BBB_MODERATOR_PASSWORD - moderator password (optional - has to be set to the moderator password of moodle/greenlight or any other frontend to allow joining via their links)
 * BBB_MEETING_TITLE - meeting title (optional - only works if the meeting is started by the liveStreaming)
+* BBB_DOWNLOAD_MEETING= - download / save BigBlueButton meeting in lossless mkv format
+* BBB_INTRO= - play intro file (can be a local file in videodata folder e.g. /video/intro.mp4 or a url of a mediastream e.g. https://my.intro.stream)
+* BBB_BEGIN_INTRO_AT=04:40 - begin the intro at position (optional, e.g. 00:00:05)
+* BBB_END_INTRO_AT= - end intro after (optional, e.g. 01:00:00 - after one hour)
 * BBB_USER_NAME - the username to join the meeting. (Default: Live)
 * BBB_SHOW_CHAT - shows the chat on the left side of the window (Default: false)
+* TZ - Timezone (Default: Europe/Vienna)
 
 #### Chat settings
 * BBB_ENABLE_CHAT - Enable Chat feedback channel
@@ -42,8 +47,6 @@ You need to set some environment variables to run the container.
 * docker-compose down 
 
 ## Known Limitations
-* You must extract and provide the meetingID, which is not visible within the room.
-* the streamer cannot join meetings, that where not started yet
 * the streamer does not reconnect, if the connection to BigBlueButton gets lost
 * when using breakoutrooms, the streamer will show the popup of the invitation and not be able to get back to the conference
 
@@ -61,15 +64,15 @@ Similar to the GDPR and  the CCPA, other local privacy law principles  also may
 Always be transparent and act upon privacy rights and federal law Regulations.
 
 ## License
-    BigBlueButton-liveStreaming is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    BigBlueButton-liveStreaming is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with BigBlueButton-liveStreaming.  If not, see [GNU website](https://www.gnu.org/licenses)
+BigBlueButton-liveStreaming is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BigBlueButton-liveStreaming is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BigBlueButton-liveStreaming.  If not, see [GNU website](https://www.gnu.org/licenses)
diff --git a/chat.py b/chat.py
index 2e908e8ced51915c69a8ecba288c83320cd1199f..e081fec3106c1ea478eb0c2e7a17ca3f6648e59f 100644
--- a/chat.py
+++ b/chat.py
@@ -21,6 +21,10 @@ parser.add_argument("-s","--server", help="Big Blue Button Server URL")
 parser.add_argument("-p","--secret", help="Big Blue Button Secret")
 parser.add_argument("-i","--id", help="Big Blue Button Meeting ID")
 parser.add_argument("-m","--moderator", help="Join the meeting as moderator",action="store_true")
+parser.add_argument("-S","--startMeeting", help="start the meeting if not running",action="store_true")
+parser.add_argument("-A","--attendeePassword", help="attendee password (required to create meetings)")
+parser.add_argument("-M","--moderatorPassword", help="moderator password (required to create a meeting)")
+parser.add_argument("-T","--meetingTitle", help="meeting title (required to create a meeting)")
 parser.add_argument("-u","--user", help="Name to join the meeting",default="Live")
 parser.add_argument("-r","--redis", help="Redis hostname",default="redis")
 parser.add_argument("-c","--channel", help="Redis channel",default="chat")
@@ -51,6 +55,13 @@ def bbb_browser():
     global browser
 
     logging.info('Open BBB for chat!!')
+    if args.startMeeting is True:
+        try:
+            logging.info("create_meeting...")
+            create_meeting()
+        except exception.bbbexception.BBBException as ERR:
+            logging.info(ERR)
+
     browser.get(get_join_url())
 
     element = EC.presence_of_element_located((By.CSS_SELECTOR, '[aria-label="Listen only"]'))
@@ -74,6 +85,16 @@ def chat_handler(message):
     browser.find_elements_by_css_selector('[aria-label="Send message"]')[0].click()
     logging.info(message['data'])
 
+def create_meeting():
+    create_params = {}
+    if args.moderatorPassword:
+        create_params['moderatorPW'] = args.moderatorPassword
+    if args.attendeePassword:
+        create_params['attendeePW'] = args.attendeePassword
+    if args.meetingTitle:
+        create_params['name'] = args.meetingTitle
+    return bbb.create_meeting(args.id, params=create_params)
+
 def get_join_url():
     minfo = bbb.get_meeting_info(args.id)
     if args.moderator:
diff --git a/examples/docker-compose.yml.example b/examples/docker-compose.yml.example
index a564f8fff7fdf38a1109d74725479f32001a67aa..9a65879c83575cd5010baf5d8853b71ad7d4ae8a 100644
--- a/examples/docker-compose.yml.example
+++ b/examples/docker-compose.yml.example
@@ -18,5 +18,18 @@ services:
       - BBB_MODERATOR_PASSWORD=JjeQYksarqLQ
       # meeting title (optional):
       - BBB_MEETING_TITLE=liveStreaming Test
+      # download / save BigBlueButton meeting
+      - BBB_DOWNLOAD_MEETING=false
+      # play intro file (can be a local file in videodata folder e.g. /video/intro.mp4 or a url of a mediastream e.g. https://my.intro.stream)
+      - BBB_INTRO=false
+      # begin the intro at position (optional, e.g. 00:00:05)
+      - BBB_BEGIN_INTRO_AT=04:40
+      # end intro after (optional, e.g. 01:00:00 - after one hour)
+      - BBB_END_INTRO_AT=
       # Media server url:
       - BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key
+      # Timezone (default: Europe/Vienna):
+      - TZ=Europe/Vienna
+
+    volumes:
+      - ./videodata:/video
diff --git a/examples/get_meetings.py b/examples/get_meetings.py
index 60045754d49ab803515dc86a74be4a2f9148fe06..75c36088ab46ccc17c9899c53d0fa23d34dae720 100755
--- a/examples/get_meetings.py
+++ b/examples/get_meetings.py
@@ -1,6 +1,11 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
+### to use this script you will need to ###
+# apt install pip3
+# pip3 install bigbluebutton_api_python
+# pip3 install pyyaml
+
 import argparse, sys, os, logging, yaml, urllib, json
 from bigbluebutton_api_python import BigBlueButton
 
@@ -8,7 +13,7 @@ logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
 
 parser = argparse.ArgumentParser()
 parser.add_argument("-s","--server", help="Big Blue Button Server URL")
-parser.add_argument("-c","--config", help="path to config file in yaml format e.g. your docker-compose.yml", default="../docker-compose.yml")
+parser.add_argument("-c","--config", help="path to config file in yaml format e.g. your docker-compose.yml", default="./docker-compose.yml")
 parser.add_argument("-p","--secret", help="Big Blue Button Secret")
 args = parser.parse_args()
 
@@ -41,10 +46,17 @@ if not args.server and not args.secret:
     sys.exit()
 
 bbb = BigBlueButton(args.server,args.secret)
-meetings = get_meetings()
-for meeting in meetings['xml']['meetings']:
-    print(meetings['xml']['meetings'][meeting]['meetingName'])
-    print("ID: {}".format(meetings['xml']['meetings'][meeting]['meetingID']))
-    print("ATTENDEE_PASSWORD: {}".format(meetings['xml']['meetings'][meeting]['attendeePW']))
-    print("MODERATOR_PASSWORD: {}".format(meetings['xml']['meetings'][meeting]['moderatorPW']))
+meetingsXML = get_meetings()
+rawMeetings = meetingsXML['xml']['meetings']['meeting']
+meetings = []
+if isinstance(rawMeetings, list):
+    meetings = rawMeetings
+else:
+    meetings.append(rawMeetings)
+
+for meeting in meetings:
+    print(meeting['meetingName'])
+    print("ID: {}".format(meeting['meetingID']))
+    print("ATTENDEE_PASSWORD: {}".format(meeting['attendeePW']))
+    print("MODERATOR_PASSWORD: {}".format(meeting['moderatorPW']))
     print("")
diff --git a/startStream.sh b/startStream.sh
index 51b5ecc49ca7f19a510c2ea4437c9af82edd4da7..361f44458aa88e7c2b7ee3873b60a72701188c20 100644
--- a/startStream.sh
+++ b/startStream.sh
@@ -6,12 +6,42 @@ then
    JOIN_AS_MODERATOR="-m";
 fi 
 
+STREAM_MEETING="";
+if [ "${BBB_STREAM_URL}" != "" ]
+then
+   STREAM_MEETING="-l -t ${BBB_STREAM_URL}";
+fi 
+
+DOWNLOAD_MEETING="";
+if [ "${BBB_DOWNLOAD_MEETING}" = "true" ]
+then
+   DOWNLOAD_MEETING="-d";
+fi 
+
 SHOW_CHAT="";
 if [ "${BBB_SHOW_CHAT}" = "true" ]
 then
    SHOW_CHAT="-c";
 fi 
 
+INTRO="";
+if [ "${BBB_INTRO}" != "" ]
+then
+   INTRO="-I ${BBB_INTRO}";
+fi 
+
+BEGIN_INTRO="";
+if [ "${BBB_BEGIN_INTRO_AT}" != "" ]
+then
+   BEGIN_INTRO="-B ${BBB_BEGIN_INTRO_AT}";
+fi 
+
+END_INTRO="";
+if [ "${BBB_END_INTRO_AT}" != "" ]
+then
+   END_INTRO="-E ${BBB_END_INTRO_AT}";
+fi 
+
 START_MEETING="";
 if [ "${BBB_START_MEETING}" != "" ]
 then
@@ -42,4 +72,4 @@ then
    sleep 10
 fi 
 
-xvfb-run -n 122 --server-args="-screen 0 1920x1080x24" python3 stream.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -t ${BBB_STREAM_URL} -u ${BBB_USER_NAME} ${SHOW_CHAT} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $JOIN_AS_MODERATOR;
+xvfb-run -n 122 --server-args="-screen 0 1920x1080x24" python3 stream.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -u ${BBB_USER_NAME} ${SHOW_CHAT} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $STREAM_MEETING $INTRO $BEGIN_INTRO $END_INTRO $JOIN_AS_MODERATOR $DOWNLOAD_MEETING;
diff --git a/stream.py b/stream.py
index b2e7db7ca2323929daceb5efa15e6131f741dd22..019c9364a2b946f33fd6750ed57c2d5664aecb5e 100644
--- a/stream.py
+++ b/stream.py
@@ -12,6 +12,9 @@ from selenium.webdriver.support.ui import WebDriverWait
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.common.by import By
 
+from datetime import datetime
+
+downloadProcess = None
 browser = None
 selelnium_timeout = 30
 connect_timeout = 5
@@ -22,6 +25,11 @@ parser = argparse.ArgumentParser()
 parser.add_argument("-s","--server", help="Big Blue Button Server URL")
 parser.add_argument("-p","--secret", help="Big Blue Button Secret")
 parser.add_argument("-i","--id", help="Big Blue Button Meeting ID")
+parser.add_argument("-I","--intro", help="Intro file to play before streaming")
+parser.add_argument("-B","--beginIntroAt", help="begin intro at position (e.g. 00:01:05)")
+parser.add_argument("-E","--endIntroAt", help="End intro at position (e.g. 01:00:04)")
+parser.add_argument("-l","--stream", help="live stream a BigBlueButton meeting",action="store_true")
+parser.add_argument("-d","--download", help="download / save a BigBlueButton meeting",action="store_true")
 parser.add_argument("-m","--moderator", help="Join the meeting as moderator",action="store_true")
 parser.add_argument("-S","--startMeeting", help="start the meeting if not running",action="store_true")
 parser.add_argument("-A","--attendeePassword", help="attendee password (required to create meetings)")
@@ -101,24 +109,57 @@ def get_join_url():
         pwd = minfo.get_meetinginfo().get_attendeepw()
     return bbb.get_join_meeting_url(args.user,args.id, pwd)
 
-def watch():
-    while True:
-        time.sleep(60)
+def stream_intro():
+    audio_options = '-f alsa -i pulse -ac 2 -c:a aac -b:a 160k -ar 44100'
+    video_options = '-c:v libx264 -x264-params "nal-hrd=cbr" -profile:v high -level:v 4.2 -vf format=yuv420p -b:v 4000k -maxrate 4000k -minrate 2000k -bufsize 8000k -g 60 -preset ultrafast'
+    introBegin = ""
+    if args.beginIntroAt:
+        introBegin = "-ss %s"%(args.beginIntroAt)
+    introEnd = ""
+    if args.endIntroAt:
+        introEnd = "-to %s"%(args.endIntroAt)
+    ffmpeg_stream = 'ffmpeg -re %s %s -thread_queue_size 1024 -i %s -thread_queue_size 1024 %s -threads 0 %s -f flv "%s"' % ( introBegin, introEnd, args.intro, audio_options, video_options, args.target)
+    ffmpeg_args = shlex.split(ffmpeg_stream)
+    logging.info("streaming intro...")
+    p = subprocess.call(ffmpeg_args)
 
 def stream():
     audio_options = '-f alsa -i pulse -ac 2 -c:a aac -b:a 160k -ar 44100'
     #video_options = ' -c:v libvpx-vp9 -b:v 2000k -crf 33 -quality realtime -speed 5'
     video_options = '-c:v libx264 -x264-params "nal-hrd=cbr" -profile:v high -level:v 4.2 -vf format=yuv420p -b:v 4000k -maxrate 4000k -minrate 2000k -bufsize 8000k -g 60 -preset ultrafast -tune zerolatency'
-    ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080  -i :%d %s -threads 0 %s -f flv -flvflags no_duration_filesize "%s"' % ( 122, audio_options, video_options, args.target)
+    ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080  -i :%d -thread_queue_size 1024 %s -threads 0 %s -f flv -flvflags no_duration_filesize "%s"' % ( 122, audio_options, video_options, args.target)
     ffmpeg_args = shlex.split(ffmpeg_stream)
-    p = subprocess.Popen(ffmpeg_args)
+    logging.info("streaming meeting...")
+    p = subprocess.call(ffmpeg_args)
+
+def download():
+    downloadFile = "/video/meeting-%s.mkv" % fileTimeStamp 
+    audio_options = '-f alsa -i pulse -ac 2'
+    video_options = '-c:v libx264rgb -crf 0 -preset ultrafast'
+    ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080  -i :%d -thread_queue_size 1024 %s %s %s' % ( 122, audio_options, video_options, downloadFile)
+    ffmpeg_args = shlex.split(ffmpeg_stream)
+    logging.info("saving meeting as %s" % downloadFile)
+    return subprocess.Popen(ffmpeg_args)
 
 if args.startMeeting is False:
     while bbb.is_meeting_running(args.id).is_meeting_running() != True:
         logging.info("Meeting isn't running. We will try again in %d seconds!" % connect_timeout)
         time.sleep(connect_timeout)
+
+# current date and time
+now = datetime.now()
+fileTimeStamp = now.strftime("%Y%m%d%H%M%S")
+
 set_up()
-bbb_browser()
-stream()
-watch()
-browser.quit()
\ No newline at end of file
+if args.stream and args.intro:
+    stream_intro()
+if args.stream or args.download:
+    bbb_browser()
+if args.download:
+    downloadProcess = download()
+if args.stream:
+    stream()
+if downloadProcess:
+    downloadProcess.communicate(input=None)
+if browser:
+    browser.quit()