def checkRTMPAuthIP(requestData): authorized = False requestIP = "0.0.0.0" if requestData.environ.get('HTTP_X_FORWARDED_FOR') is None: requestIP = requestData.environ['REMOTE_ADDR'] else: requestIP = requestData.environ['HTTP_X_FORWARDED_FOR'] authorizedRTMPServers = settings.rtmpServer.query.all() receivedIP = requestIP ipList = requestIP.split(',') confirmedIP = "" for ip in ipList: parsedip = ip.strip() for server in authorizedRTMPServers: if authorized is False: if server.active is True: resolveResults = socket.getaddrinfo(server.address, 0) for resolved in resolveResults: if parsedip == resolved[4][0]: authorized = True confirmedIP = resolved[4][0] if authorized is False: confirmedIP = receivedIP system.newLog(1, "Unauthorized RTMP Server - " + confirmedIP) return (authorized, confirmedIP)
def deleteClip(clipID): clipQuery = RecordedVideo.Clips.query.filter_by(id=int(clipID)).first() videos_root = globalvars.videoRoot + 'videos/' if current_user.id == clipQuery.recordedVideo.owningUser and clipQuery is not None: videoPath = videos_root + clipQuery.videoLocation thumbnailPath = videos_root + clipQuery.thumbnailLocation gifPath = videos_root + clipQuery.gifLocation if thumbnailPath != videos_root: if os.path.exists(thumbnailPath) and (thumbnailPath is not None or thumbnailPath != ""): os.remove(thumbnailPath) if gifPath != videos_root: if os.path.exists(gifPath) and (clipQuery.gifLocation is not None or gifPath != ""): os.remove(gifPath) if videoPath != videos_root: if os.path.exists(videoPath) and (clipQuery.videoLocation is not None or videoPath != ""): os.remove(videoPath) db.session.delete(clipQuery) db.session.commit() system.newLog(6, "Clip Deleted - ID #" + str(clipID)) return True else: return False
def page_not_found(e): sysSettings = settings.settings.query.first() system.newLog(0, "500 Error - " + str(request.url)) return render_template(themes.checkOverride('500.html'), sysSetting=sysSettings, previous=request.referrer, error=e), 500
def testWebhook(webhookType, webhookID, **kwargs): system.newLog( 8, "Testing Webhook for ID #" + str(webhookID) + ", Type: " + webhookType) webhookQuery = None if webhookType == "channel": webhookQuery = webhook.webhook.query.filter_by(id=webhookID).first() elif webhookType == "global": webhookQuery = webhook.globalWebhook.query.filter_by( id=webhookID).first() if webhookQuery is not None: url = webhookQuery.endpointURL payload = processWebhookVariables(webhookQuery.requestPayload, **kwargs) header = json.loads(webhookQuery.requestHeader) requestType = webhookQuery.requestType try: if requestType == 0: r = requests.post(url, headers=header, data=payload) elif requestType == 1: r = requests.get(url, headers=header, data=payload) elif requestType == 2: r = requests.put(url, headers=header, data=payload) elif requestType == 3: r = requests.delete(url, headers=header, data=payload) except Exception as e: print("Webhook Error-" + str(e)) system.newLog( 8, "Completed Webhook Test for ID #" + str(webhookQuery.id) + " - Destination:" + str(url))
def deleteVideo(videoID): recordedVid = RecordedVideo.RecordedVideo.query.filter_by( id=videoID).first() if current_user.id == recordedVid.owningUser and recordedVid.videoLocation is not None: videos_root = globalvars.videoRoot + 'videos/' filePath = videos_root + recordedVid.videoLocation thumbnailPath = videos_root + recordedVid.videoLocation[:-4] + ".png" gifPath = videos_root + recordedVid.videoLocation[:-4] + ".gif" if filePath != videos_root: if os.path.exists(filePath) and ( recordedVid.videoLocation is not None or recordedVid.videoLocation != ""): os.remove(filePath) if os.path.exists(thumbnailPath): os.remove(thumbnailPath) if os.path.exists(gifPath): os.remove(gifPath) # Delete Clips Attached to Video for clip in recordedVid.clips: thumbnailPath = videos_root + clip.thumbnailLocation if thumbnailPath != videos_root: if os.path.exists(thumbnailPath) and ( clip.thumbnailLocation is not None or clip.thumbnailLocation != ""): os.remove(thumbnailPath) db.session.delete(clip) # Delete Upvotes Attached to Video upvoteQuery = upvotes.videoUpvotes.query.filter_by( videoID=recordedVid.id).all() for vote in upvoteQuery: db.session.delete(vote) # Delete Comments Attached to Video commentQuery = comments.videoComments.query.filter_by( videoID=recordedVid.id).all() for comment in commentQuery: db.session.delete(comment) # Delete Views Attached to Video viewQuery = views.views.query.filter_by(viewType=1, itemID=recordedVid.id).all() for view in viewQuery: db.session.delete(view) db.session.delete(recordedVid) db.session.commit() system.newLog(4, "Video Deleted - ID #" + str(videoID)) return True return False
def upload(): videos_root = globalvars.videoRoot + 'videos/' sysSettings = settings.settings.query.first() if not sysSettings.allowUploads: db.session.close() return "Video Uploads Disabled", 501 if request.files['file']: if not os.path.exists(videos_root + 'temp'): os.makedirs(videos_root + 'temp') file = request.files['file'] if request.form['ospfilename'] != "": ospfilename = request.form['ospfilename'] else: return "Ooops.", 500 if system.videoupload_allowedExt( file.filename, current_app.config['VIDEO_UPLOAD_EXTENSIONS']): save_path = os.path.join( current_app.config['VIDEO_UPLOAD_TEMPFOLDER'], secure_filename(ospfilename)) current_chunk = int(request.form['dzchunkindex']) else: system.newLog( 4, "File Upload Failed - File Type not Allowed - Username:"******"Filetype not allowed", 403 if current_chunk > 4500: open(save_path, 'w').close() return "File is getting too large.", 403 if os.path.exists(save_path) and current_chunk == 0: open(save_path, 'w').close() try: with open(save_path, 'ab') as f: f.seek(int(request.form['dzchunkbyteoffset'])) f.write(file.stream.read()) except OSError: system.newLog( 4, "File Upload Failed - OSError - Username:"******"Ooops.", 500 total_chunks = int(request.form['dztotalchunkcount']) if current_chunk + 1 == total_chunks: if os.path.getsize(save_path) != int( request.form['dztotalfilesize']): return "Size mismatch", 500 return "success", 200 else: return "I don't understand", 501
def rtmp_stage2_user_auth_check(channelLoc, ipaddress): sysSettings = settings.settings.query.first() currentTime = datetime.datetime.utcnow() requestedChannel = Channel.Channel.query.filter_by(channelLoc=channelLoc).first() if requestedChannel is not None: authedStream = Stream.Stream.query.filter_by(streamKey=requestedChannel.streamKey).first() if authedStream is not None: authedStream.currentViewers = int(xmpp.getChannelCounts(requestedChannel.channelLoc)) authedStream.totalViewers = int(xmpp.getChannelCounts(requestedChannel.channelLoc)) db.session.commit() if requestedChannel.imageLocation is None: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/static/img/video-placeholder.jpg") else: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/images/" + requestedChannel.imageLocation) webhookFunc.runWebhook(requestedChannel.id, 0, channelname=requestedChannel.channelName, channelurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/channel/" + str(requestedChannel.id)), channeltopic=requestedChannel.topic, channelimage=channelImage, streamer=templateFilters.get_userName(requestedChannel.owningUser), channeldescription=str(requestedChannel.description), streamname=authedStream.streamName, streamurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/view/" + requestedChannel.channelLoc), streamtopic=templateFilters.get_topicName(authedStream.topic), streamimage=(sysSettings.siteProtocol + sysSettings.siteAddress + "/stream-thumb/" + requestedChannel.channelLoc + ".png")) subscriptionQuery = subscriptions.channelSubs.query.filter_by(channelID=requestedChannel.id).all() for sub in subscriptionQuery: # Create Notification for Channel Subs newNotification = notifications.userNotification(templateFilters.get_userName(requestedChannel.owningUser) + " has started a live stream in " + requestedChannel.channelName, "/view/" + str(requestedChannel.channelLoc), "/images/" + str(requestedChannel.owner.pictureLocation), sub.userID) db.session.add(newNotification) db.session.commit() try: subsFunc.processSubscriptions(requestedChannel.id, sysSettings.siteName + " - " + requestedChannel.channelName + " has started a stream", "<html><body><img src='" + sysSettings.siteProtocol + sysSettings.siteAddress + sysSettings.systemLogo + "'><p>Channel " + requestedChannel.channelName + " has started a new video stream.</p><p>Click this link to watch<br><a href='" + sysSettings.siteProtocol + sysSettings.siteAddress + "/view/" + str(requestedChannel.channelLoc) + "'>" + requestedChannel.channelName + "</a></p>") except: system.newLog(0, "Subscriptions Failed due to possible misconfiguration") returnMessage = {'time': str(currentTime), 'request': 'Stage2', 'success': True, 'channelLoc': requestedChannel.channelLoc, 'ipAddress': str(ipaddress), 'message': 'Success - Stream Authenticated & Initialized'} db.session.close() return returnMessage else: returnMessage = {'time': str(currentTime), 'request': 'Stage2', 'success': False, 'channelLoc': requestedChannel.channelLoc, 'ipAddress': str(ipaddress), 'message': 'Failed - No Matching Stage 1 Connection'} db.session.close() return returnMessage else: returnMessage = {'time': str(currentTime), 'request': 'Stage2', 'success': False, 'channelLoc': channelLoc, 'ipAddress': str(ipaddress), 'message': 'Failed - Passed Stage 1 Channel ID Does Not Match Any Known Channels'} db.session.close() return returnMessage
def deleteChannelAdmin(message): channelID = int(message['channelID']) channelQuery = Channel.Channel.query.filter_by(id=channelID).first() if channelQuery is not None: if current_user.has_role( 'Admin') or channelQuery.owningUser == current_user.id: for vid in channelQuery.recordedVideo: for upvote in vid.upvotes: db.session.delete(upvote) vidComments = vid.comments for comment in vidComments: db.session.delete(comment) vidViews = views.views.query.filter_by(viewType=1, itemID=vid.id) for view in vidViews: db.session.delete(view) for clip in vid.clips: db.session.delete(clip) db.session.delete(vid) for upvote in channelQuery.upvotes: db.session.delete(upvote) for inviteCode in channelQuery.inviteCodes: db.session.delete(inviteCode) for viewer in channelQuery.invitedViewers: db.session.delete(viewer) for sub in channelQuery.subscriptions: db.session.delete(sub) for hook in channelQuery.webhooks: db.session.delete(hook) for sticker in channelQuery.chatStickers: db.session.delete(sticker) stickerFolder = '/var/www/images/stickers/' + channelQuery.channelLoc + '/' shutil.rmtree(stickerFolder, ignore_errors=True) filePath = globalvars.videoRoot + channelQuery.channelLoc if filePath != globalvars.videoRoot: shutil.rmtree(filePath, ignore_errors=True) from app import ejabberd sysSettings = settings.settings.query.first() ejabberd.destroy_room(channelQuery.channelLoc, 'conference.' + sysSettings.siteAddress) system.newLog( 1, "User " + current_user.username + " deleted Channel " + str(channelQuery.id)) db.session.delete(channelQuery) db.session.commit() db.session.close() return 'OK'
def disable_2fa(msg): if current_user.has_role('Admin'): userID = int(msg['userID']) userQuery = Sec.User.query.filter_by(id=userID).first() if userQuery is not None: userQuery.tf_primary_method = None userQuery.tf_totp_secret = None db.session.commit() system.newLog( 1, "User " + current_user.username + " disabled 2FA for " + str(userQuery.username)) db.session.close() return 'OK'
def processSubscriptions(channelID, subject, message): subscriptionQuery = subscriptions.channelSubs.query.filter_by(channelID=channelID).all() if subscriptionQuery: system.newLog(2, "Sending Subscription Emails for Channel ID: " + str(channelID)) subCount = 0 for sub in subscriptionQuery: userQuery = Sec.User.query.filter_by(id=int(sub.userID)).first() if userQuery is not None: result = runSubscription(subject, userQuery.email, message) subCount = subCount + 1 system.newLog(2, "Processed " + str(subCount) + " out of " + str(len(subscriptionQuery)) + " Email Subscriptions for Channel ID: " + str(channelID) ) return True
def changeVideoMetadata(videoID, newVideoName, newVideoTopic, description, allowComments): recordedVidQuery = RecordedVideo.RecordedVideo.query.filter_by( id=videoID, owningUser=current_user.id).first() sysSettings = settings.settings.query.first() if recordedVidQuery is not None: recordedVidQuery.channelName = system.strip_html(newVideoName) recordedVidQuery.topic = newVideoTopic recordedVidQuery.description = system.strip_html(description) recordedVidQuery.allowComments = allowComments if recordedVidQuery.channel.imageLocation is None: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/static/img/video-placeholder.jpg") else: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/images/" + recordedVidQuery.channel.imageLocation) webhookFunc.runWebhook( recordedVidQuery.channel.id, 9, channelname=recordedVidQuery.channel.channelName, channelurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/channel/" + str(recordedVidQuery.channel.id)), channeltopic=templateFilters.get_topicName( recordedVidQuery.channel.topic), channelimage=channelImage, streamer=templateFilters.get_userName( recordedVidQuery.channel.owningUser), channeldescription=str(recordedVidQuery.channel.description), videoname=recordedVidQuery.channelName, videodate=recordedVidQuery.videoDate, videodescription=recordedVidQuery.description, videotopic=templateFilters.get_topicName(recordedVidQuery.topic), videourl=(sysSettings.siteProtocol + sysSettings.siteAddress + '/videos/' + recordedVidQuery.videoLocation), videothumbnail=(sysSettings.siteProtocol + sysSettings.siteAddress + '/videos/' + recordedVidQuery.thumbnailLocation)) db.session.commit() system.newLog( 4, "Video Metadata Changed - ID # " + str(recordedVidQuery.id)) return True return False
def changeClipMetadata(clipID, name, description): # TODO Add Webhook for Clip Metadata Change clipQuery = RecordedVideo.Clips.query.filter_by(id=int(clipID)).first() if clipQuery is not None: if clipQuery.recordedVideo.owningUser == current_user.id: clipQuery.clipName = system.strip_html(name) clipQuery.description = system.strip_html(description) db.session.commit() system.newLog(6, "Clip Metadata Changed - ID #" + str(clipID)) return True return False
def user_registered_sighandler(app, user, confirm_token): defaultRoleQuery = Sec.Role.query.filter_by(default=True) for role in defaultRoleQuery: user_datastore.add_role_to_user(user, role.name) user.authType = 0 user.xmppToken = str(os.urandom(32).hex()) user.uuid = str(uuid.uuid4()) webhookFunc.runWebhook("ZZZ", 20, user=user.username) system.newLog(1, "A New User has Registered - Username:"******"An email has been sent to the email provided. Please check your email and verify your account to activate." ) db.session.commit()
def runWebhook(channelID, triggerType, **kwargs): webhookQueue = [] if channelID != "ZZZ": webhookQuery = webhook.webhook.query.filter_by( channelID=channelID, requestTrigger=triggerType).all() webhookQueue.append(webhookQuery) globalWebhookQuery = webhook.globalWebhook.query.filter_by( requestTrigger=triggerType).all() webhookQueue.append(globalWebhookQuery) for queue in webhookQueue: if queue: for hook in queue: url = hook.endpointURL payload = processWebhookVariables(hook.requestPayload, **kwargs) header = json.loads(hook.requestHeader) requestType = hook.requestType try: if requestType == 0: r = requests.post(url, headers=header, data=payload) elif requestType == 1: r = requests.get(url, headers=header, data=payload) elif requestType == 2: r = requests.put(url, headers=header, data=payload) elif requestType == 3: r = requests.delete(url, headers=header, data=payload) except: pass system.newLog( 8, "Processing Webhook for ID #" + str(hook.id) + " - Destination:" + str(url)) db.session.commit() db.session.close() return True
def upload_vid(): sysSettings = settings.settings.query.first() if not sysSettings.allowUploads: db.session.close() flash("Video Upload Disabled", "error") return redirect(url_for('root.main_page')) currentTime = datetime.datetime.now() channel = int(request.form['uploadToChannelID']) topic = int(request.form['uploadTopic']) thumbnailFilename = request.form['thumbnailFilename'] videoFilename= request.form['videoFilename'] ChannelQuery = Channel.Channel.query.filter_by(id=channel).first() if ChannelQuery.owningUser != current_user.id: flash('You are not allowed to upload to this channel!') db.session.close() return redirect(url_for('root.main_page')) videoPublishState = ChannelQuery.autoPublish newVideo = RecordedVideo.RecordedVideo(current_user.id, channel, ChannelQuery.channelName, ChannelQuery.topic, 0, "", currentTime, ChannelQuery.allowComments, videoPublishState) videoLoc = ChannelQuery.channelLoc + "/" + videoFilename.rsplit(".", 1)[0] + '_' + datetime.datetime.strftime(currentTime, '%Y%m%d_%H%M%S') + ".mp4" videos_root = current_app.config['WEB_ROOT'] + 'videos/' videoPath = videos_root + videoLoc if videoFilename != "": if not os.path.isdir(videos_root + ChannelQuery.channelLoc): try: os.mkdir(videos_root + ChannelQuery.channelLoc) except OSError: system.newLog(4, "File Upload Failed - OSError - Unable to Create Directory - Username:"******"Error uploading video - Unable to create directory","error") db.session.close() return redirect(url_for("root.main_page")) shutil.move(current_app.config['VIDEO_UPLOAD_TEMPFOLDER'] + '/' + videoFilename, videoPath) else: db.session.close() flash("Error uploading video - Couldn't move video file") return redirect(url_for('root.main_page')) newVideo.videoLocation = videoLoc if thumbnailFilename != "": thumbnailLoc = ChannelQuery.channelLoc + '/' + thumbnailFilename.rsplit(".", 1)[0] + '_' + datetime.datetime.strftime(currentTime, '%Y%m%d_%H%M%S') + videoFilename.rsplit(".", 1)[-1] thumbnailPath = videos_root + thumbnailLoc try: shutil.move(current_app.config['VIDEO_UPLOAD_TEMPFOLDER'] + '/' + thumbnailFilename, thumbnailPath) except: flash("Thumbnail Upload Failed Due to Missing File","error") newVideo.thumbnailLocation = thumbnailLoc else: thumbnailLoc = ChannelQuery.channelLoc + '/' + videoFilename.rsplit(".", 1)[0] + '_' + datetime.datetime.strftime(currentTime, '%Y%m%d_%H%M%S') + ".png" subprocess.call(['ffmpeg', '-ss', '00:00:01', '-i', videos_root + videoLoc, '-s', '384x216', '-vframes', '1', videos_root + thumbnailLoc]) newVideo.thumbnailLocation = thumbnailLoc newGifFullThumbnailLocation = ChannelQuery.channelLoc + '/' + videoFilename.rsplit(".", 1)[0] + '_' + datetime.datetime.strftime(currentTime, '%Y%m%d_%H%M%S') + ".gif" gifresult = subprocess.call(['ffmpeg', '-ss', '00:00:01', '-t', '3', '-i', videos_root + videoLoc, '-filter_complex', '[0:v] fps=30,scale=w=384:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1', '-y', videos_root + newGifFullThumbnailLocation]) newVideo.gifLocation = newGifFullThumbnailLocation if request.form['videoTitle'] != "": newVideo.channelName = system.strip_html(request.form['videoTitle']) else: newVideo.channelName = currentTime newVideo.topic = topic newVideo.description = system.strip_html(request.form['videoDescription']) if os.path.isfile(videoPath): newVideo.pending = False db.session.add(newVideo) db.session.commit() if ChannelQuery.autoPublish is True: newVideo.published = True else: newVideo.published = False db.session.commit() if ChannelQuery.imageLocation is None: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/static/img/video-placeholder.jpg") else: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/images/" + ChannelQuery.imageLocation) system.newLog(4, "File Upload Successful - Username:"******"/channel/" + str(ChannelQuery.id)), channeltopic=templateFilters.get_topicName(ChannelQuery.topic), channelimage=channelImage, streamer=templateFilters.get_userName(ChannelQuery.owningUser), channeldescription=str(ChannelQuery.description), videoname=newVideo.channelName, videodate=newVideo.videoDate, videodescription=newVideo.description, videotopic=templateFilters.get_topicName(newVideo.topic), videourl=(sysSettings.siteProtocol + sysSettings.siteAddress + '/play/' + str(newVideo.id)), videothumbnail=(sysSettings.siteProtocol + sysSettings.siteAddress + '/videos/' + newVideo.thumbnailLocation)) subscriptionQuery = subscriptions.channelSubs.query.filter_by(channelID=ChannelQuery.id).all() for sub in subscriptionQuery: # Create Notification for Channel Subs newNotification = notifications.userNotification(templateFilters.get_userName(ChannelQuery.owningUser) + " has posted a new video to " + ChannelQuery.channelName + " titled " + newVideo.channelName, '/play/' + str(newVideo.id), "/images/" + ChannelQuery.owner.pictureLocation, sub.userID) db.session.add(newNotification) db.session.commit() try: subsFunc.processSubscriptions(ChannelQuery.id, sysSettings.siteName + " - " + ChannelQuery.channelName + " has posted a new video", "<html><body><img src='" + sysSettings.siteProtocol + sysSettings.siteAddress + sysSettings.systemLogo + "'><p>Channel " + ChannelQuery.channelName + " has posted a new video titled <u>" + newVideo.channelName + "</u> to the channel.</p><p>Click this link to watch<br><a href='" + sysSettings.siteProtocol + sysSettings.siteAddress + "/play/" + str(newVideo.id) + "'>" + newVideo.channelName + "</a></p>") except: system.newLog(0, "Subscriptions Failed due to possible misconfiguration") videoID = newVideo.id db.session.commit() db.session.close() flash("Video upload complete") return redirect(url_for('play.view_vid_page', videoID=videoID))
def user_auth_check(): sysSettings = settings.settings.query.first() key = request.form['name'] ipaddress = request.form['addr'] requestedChannel = Channel.Channel.query.filter_by(channelLoc=key).first() if requestedChannel is not None: authedStream = Stream.Stream.query.filter_by( streamKey=requestedChannel.streamKey).first() if authedStream is not None: returnMessage = { 'time': str(datetime.datetime.now()), 'status': 'Successful Channel Auth', 'key': str(requestedChannel.streamKey), 'channelName': str(requestedChannel.channelName), 'ipAddress': str(ipaddress) } print(returnMessage) if requestedChannel.imageLocation is None: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/static/img/video-placeholder.jpg") else: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/images/" + requestedChannel.imageLocation) webhookFunc.runWebhook( requestedChannel.id, 0, channelname=requestedChannel.channelName, channelurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/channel/" + str(requestedChannel.id)), channeltopic=requestedChannel.topic, channelimage=channelImage, streamer=templateFilters.get_userName( requestedChannel.owningUser), channeldescription=str(requestedChannel.description), streamname=authedStream.streamName, streamurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/view/" + requestedChannel.channelLoc), streamtopic=templateFilters.get_topicName(authedStream.topic), streamimage=(sysSettings.siteProtocol + sysSettings.siteAddress + "/stream-thumb/" + requestedChannel.channelLoc + ".png")) subscriptionQuery = subscriptions.channelSubs.query.filter_by( channelID=requestedChannel.id).all() for sub in subscriptionQuery: # Create Notification for Channel Subs newNotification = notifications.userNotification( templateFilters.get_userName(requestedChannel.owningUser) + " has started a live stream in " + requestedChannel.channelName, "/view/" + str(requestedChannel.channelLoc), "/images/" + str(requestedChannel.owner.pictureLocation), sub.userID) db.session.add(newNotification) db.session.commit() try: subsFunc.processSubscriptions( requestedChannel.id, sysSettings.siteName + " - " + requestedChannel.channelName + " has started a stream", "<html><body><img src='" + sysSettings.siteProtocol + sysSettings.siteAddress + sysSettings.systemLogo + "'><p>Channel " + requestedChannel.channelName + " has started a new video stream.</p><p>Click this link to watch<br><a href='" + sysSettings.siteProtocol + sysSettings.siteAddress + "/view/" + str(requestedChannel.channelLoc) + "'>" + requestedChannel.channelName + "</a></p>") except: system.newLog( 0, "Subscriptions Failed due to possible misconfiguration") inputLocation = "rtmp://" + coreNginxRTMPAddress + ":1935/live/" + requestedChannel.channelLoc # Begin RTMP Restream Function if requestedChannel.restreamDestinations != []: globalvars.restreamSubprocesses[ requestedChannel.channelLoc] = [] for rtmpRestream in requestedChannel.restreamDestinations: if rtmpRestream.enabled == True: p = subprocess.Popen([ "ffmpeg", "-i", inputLocation, "-c", "copy", "-f", "flv", rtmpRestream.url, "-c:v", "libx264", "-maxrate", str(sysSettings.restreamMaxBitrate) + "k", "-bufsize", "6000k", "-c:a", "aac", "-b:a", "160k", "-ac", "2" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) globalvars.restreamSubprocesses[ requestedChannel.channelLoc].append(p) # Start OSP Edge Nodes ospEdgeNodeQuery = settings.edgeStreamer.query.filter_by( active=True).all() if ospEdgeNodeQuery is not []: globalvars.edgeRestreamSubprocesses[ requestedChannel.channelLoc] = [] for node in ospEdgeNodeQuery: if node.address != sysSettings.siteAddress: subprocessConstructor = [ "ffmpeg", "-i", inputLocation, "-c", "copy" ] subprocessConstructor.append("-f") subprocessConstructor.append("flv") if sysSettings.adaptiveStreaming: subprocessConstructor.append( "rtmp://" + node.address + "/stream-data-adapt/" + requestedChannel.channelLoc) else: subprocessConstructor.append( "rtmp://" + node.address + "/stream-data/" + requestedChannel.channelLoc) p = subprocess.Popen(subprocessConstructor, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) globalvars.edgeRestreamSubprocesses[ requestedChannel.channelLoc].append(p) db.session.close() return 'OK' else: returnMessage = { 'time': str(datetime.datetime.now()), 'status': 'Failed Channel Auth. No Authorized Stream Key', 'channelName': str(key), 'ipAddress': str(ipaddress) } print(returnMessage) db.session.close() return abort(400) else: returnMessage = { 'time': str(datetime.datetime.now()), 'status': 'Failed Channel Auth. Channel Loc does not match Channel', 'channelName': str(key), 'ipAddress': str(ipaddress) } print(returnMessage) db.session.close() return abort(400)
def createClip(videoID, clipStart, clipStop, clipName, clipDescription): settingsQuery = settings.settings.query.first() # TODO Add Webhook for Clip Creation recordedVidQuery = RecordedVideo.RecordedVideo.query.filter_by( id=int(videoID), owningUser=current_user.id).first() if recordedVidQuery is not None: clipLength = clipStop - clipStart if settingsQuery.maxClipLength < 301: if clipLength > settingsQuery.maxClipLength: return False, None if clipStop > clipStart: videos_root = globalvars.videoRoot + 'videos/' # Generate Clip Object newClip = RecordedVideo.Clips(recordedVidQuery.id, None, clipStart, clipStop, clipName, clipDescription) newClip.published = False db.session.add(newClip) db.session.commit() newClipQuery = RecordedVideo.Clips.query.filter_by( id=newClip.id).first() videoLocation = videos_root + recordedVidQuery.videoLocation # Establish Locations for Clips and Thumbnails clipVideoLocation = recordedVidQuery.channel.channelLoc + '/clips/' + 'clip-' + str( newClipQuery.id) + ".mp4" clipThumbNailLocation = recordedVidQuery.channel.channelLoc + '/clips/' + 'clip-' + str( newClipQuery.id) + ".png" clipGifLocation = recordedVidQuery.channel.channelLoc + '/clips/' + 'clip-' + str( newClipQuery.id) + ".gif" # Set Clip Object Values for Locations newClipQuery.videoLocation = clipVideoLocation newClipQuery.thumbnailLocation = clipThumbNailLocation newClipQuery.gifLocation = clipGifLocation # Set Full Path for Locations to be handled by FFMPEG fullvideoLocation = videos_root + clipVideoLocation fullthumbnailLocation = videos_root + clipThumbNailLocation fullgifLocation = videos_root + clipGifLocation # Create Clip Directory if doesn't exist if not os.path.isdir(videos_root + recordedVidQuery.channel.channelLoc + '/clips'): os.mkdir(videos_root + recordedVidQuery.channel.channelLoc + '/clips') # FFMPEG Subprocess to Clip Video and generate Thumbnails clipVideo = subprocess.call([ 'ffmpeg', '-ss', str(clipStart), '-i', videoLocation, '-t', str(newClipQuery.length), fullvideoLocation ]) processResult = subprocess.call([ 'ffmpeg', '-ss', str(clipStart), '-i', videoLocation, '-s', '384x216', '-vframes', '1', fullthumbnailLocation ]) gifprocessResult = subprocess.call([ 'ffmpeg', '-ss', str(clipStart), '-t', '3', '-i', videoLocation, '-filter_complex', '[0:v] fps=30,scale=w=384:h=-1,split [a][b];[a] palettegen=stats_mode=single [p];[b][p] paletteuse=new=1', '-y', fullgifLocation ]) redirectID = newClipQuery.id newClipQuery.published = True system.newLog(6, "New Clip Created - ID #" + str(redirectID)) subscriptionQuery = subscriptions.channelSubs.query.filter_by( channelID=recordedVidQuery.channel.id).all() for sub in subscriptionQuery: # Create Notification for Channel Subs newNotification = notifications.userNotification( templateFilters.get_userName(recordedVidQuery.owningUser) + " has posted a new clip to " + recordedVidQuery.channel.channelName + " titled " + clipName, '/clip/' + str(newClipQuery.id), "/images/" + str(recordedVidQuery.channel.owner.pictureLocation), sub.userID) db.session.add(newNotification) db.session.commit() db.session.close() return True, redirectID return False, None
def moveVideo(videoID, newChannel): recordedVidQuery = RecordedVideo.RecordedVideo.query.filter_by( id=int(videoID), owningUser=current_user.id).first() if recordedVidQuery is not None: newChannelQuery = Channel.Channel.query.filter_by( id=newChannel, owningUser=current_user.id).first() if newChannelQuery is not None: videos_root = globalvars.videoRoot + 'videos/' recordedVidQuery.channelID = newChannelQuery.id coreVideo = (recordedVidQuery.videoLocation.split("/")[1]).split( "_", 1)[1] if not os.path.isdir(videos_root + newChannelQuery.channelLoc): try: os.mkdir(videos_root + newChannelQuery.channelLoc) except OSError: system.newLog( 4, "Error Moving Video ID #" + str(recordedVidQuery.id) + "to Channel ID" + str(newChannelQuery.id) + "/" + newChannelQuery.channelLoc) flash("Error Moving Video - Unable to Create Directory", "error") return False shutil.move( videos_root + recordedVidQuery.videoLocation, videos_root + newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreVideo) recordedVidQuery.videoLocation = newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreVideo if (recordedVidQuery.thumbnailLocation is not None) and ( os.path.exists(videos_root + recordedVidQuery.thumbnailLocation)): coreThumbnail = ( recordedVidQuery.thumbnailLocation.split("/")[1]).split( "_", 1)[1] coreThumbnailGif = ( recordedVidQuery.gifLocation.split("/")[1]).split("_", 1)[1] shutil.move( videos_root + recordedVidQuery.thumbnailLocation, videos_root + newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreThumbnail) if (recordedVidQuery.gifLocation is not None) and ( os.path.exists(videos_root + recordedVidQuery.gifLocation)): shutil.move( videos_root + recordedVidQuery.gifLocation, videos_root + newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreThumbnailGif) recordedVidQuery.thumbnailLocation = newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreThumbnail recordedVidQuery.gifLocation = newChannelQuery.channelLoc + "/" + newChannelQuery.channelLoc + "_" + coreThumbnailGif for clip in recordedVidQuery.clips: coreThumbnail = (clip.thumbnailLocation.split("/")[2]) if not os.path.isdir(videos_root + newChannelQuery.channelLoc + '/clips'): try: os.mkdir(videos_root + newChannelQuery.channelLoc + '/clips') except OSError: system.newLog( 4, "Error Moving Video ID #" + str(recordedVidQuery.id) + "to Channel ID" + str(newChannelQuery.id) + "/" + newChannelQuery.channelLoc) flash( "Error Moving Video - Unable to Create Clips Directory", "error") return False newClipLocation = videos_root + newChannelQuery.channelLoc + "/clips/" + coreThumbnail shutil.move(videos_root + clip.thumbnailLocation, newClipLocation) clip.thumbnailLocation = newChannelQuery.channelLoc + "/clips/" + coreThumbnail db.session.commit() system.newLog( 4, "Video ID #" + str(recordedVidQuery.id) + "Moved to Channel ID" + str(newChannelQuery.id) + "/" + newChannelQuery.channelLoc) return True return False
user.xmppToken = str(os.urandom(32).hex()) user.uuid = str(uuid.uuid4()) webhookFunc.runWebhook("ZZZ", 20, user=user.username) system.newLog(1, "A New User has Registered - Username:"******"An email has been sent to the email provided. Please check your email and verify your account to activate." ) db.session.commit() #----------------------------------------------------------------------------# # Additional Handlers. #----------------------------------------------------------------------------# @app.teardown_appcontext def shutdown_session(exception=None): db.session.remove() #----------------------------------------------------------------------------# # Finalize App Init #----------------------------------------------------------------------------# system.newLog( "0", "OSP Started Up Successfully - version: " + str(globalvars.version)) if __name__ == '__main__': app.jinja_env.auto_reload = False app.config['TEMPLATES_AUTO_RELOAD'] = False socketio.run(app, Debug=config.debugMode)
def oAuthAuthorize(provider): oAuthClient = oauth.create_client(provider) oAuthProviderQuery = settings.oAuthProvider.query.filter_by( name=provider).first() if oAuthProviderQuery is not None: try: token = oAuthClient.authorize_access_token() except: return redirect('/login') userData = oAuthClient.get(oAuthProviderQuery.profile_endpoint) userDataDict = userData.json() userQuery = Sec.User.query.filter_by( oAuthID=userDataDict[oAuthProviderQuery.id_value], oAuthProvider=provider, authType=1).first() # Default expiration time to 365 days into the future if 'expires_at' not in token: if 'expires_in' in token: token['expires_at'] = datetime.timedelta(seconds=int( token['exipires_in'])) + datetime.datetime.utcnow() else: token['expires_at'] = time() + (365 * 24 * 3600) # If oAuth ID, Provider, and Auth Type Match - Initiate Login if userQuery is not None: existingTokenQuery = Sec.OAuth2Token.query.filter_by( user=userQuery.id).all() for existingToken in existingTokenQuery: db.session.delete(existingToken) db.session.commit() newToken = None if 'refresh_token' in token: newToken = Sec.OAuth2Token(provider, token['token_type'], token['access_token'], token['refresh_token'], token['expires_at'], userQuery.id) else: newToken = Sec.OAuth2Token(provider, token['token_type'], token['access_token'], None, token['expires_at'], userQuery.id) db.session.add(newToken) db.session.commit() if userQuery.active is False: flash( "User has been Disabled. Please contact your administrator", "error") return redirect('/login') else: login_user(userQuery) if oAuthProviderQuery.preset_auth_type == "Discord": discord_processLogin(userDataDict, userQuery) elif oAuthProviderQuery.preset_auth_type == "Reddit": reddit_processLogin(userDataDict, userQuery) elif oAuthProviderQuery.preset_auth_type == "Facebook": facebook_processLogin(oAuthProviderQuery.api_base_url, userDataDict, userQuery) if userQuery.email is None or userQuery.email == 'None': flash("Please Add an Email Address to your User Profile", "error") return redirect(url_for('settings.user_page')) else: return redirect(url_for('root.main_page')) # If No Match, Determine if a User Needs to be created else: existingEmailQuery = None hasEmail = False if oAuthProviderQuery.email_value in userDataDict: existingEmailQuery = Sec.User.query.filter_by( email=userDataDict[ oAuthProviderQuery.email_value]).first() hasEmail = True else: flash("Please Add an Email Address to your User Profile", "error") # No Username Match - Create New User if existingEmailQuery is None: convertedUsername = userDataDict[ oAuthProviderQuery.username_value].replace(" ", "_") userDataDict[ oAuthProviderQuery.username_value] = convertedUsername existingUsernameQuery = Sec.User.query.filter_by( username=convertedUsername).first() requestedUsername = convertedUsername if existingUsernameQuery is not None: requestedUsername = requestedUsername + str( random.randint(1, 9999)) if hasEmail is True: user_datastore.create_user( email=userDataDict[oAuthProviderQuery.email_value], username=requestedUsername, active=True, confirmed_at=datetime.datetime.utcnow(), authType=1, oAuthID=userDataDict[oAuthProviderQuery.id_value], oAuthProvider=provider) else: user_datastore.create_user( email=None, username=requestedUsername, active=True, confirmed_at=datetime.datetime.utcnow(), authType=1, oAuthID=userDataDict[oAuthProviderQuery.id_value], oAuthProvider=provider) db.session.commit() user = Sec.User.query.filter_by( username=requestedUsername).first() defaultRoleQuery = Sec.Role.query.filter_by(default=True) for role in defaultRoleQuery: user_datastore.add_role_to_user(user, role.name) user.uuid = str(uuid.uuid4()) user.xmppToken = str(os.urandom(32).hex()) if oAuthProviderQuery.preset_auth_type == "Discord": discord_processLogin(userDataDict, user) elif oAuthProviderQuery.preset_auth_type == "Reddit": reddit_processLogin(userDataDict, user) elif oAuthProviderQuery.preset_auth_type == "Facebook": facebook_processLogin(oAuthProviderQuery.api_base_url, userDataDict, user) newToken = None if 'refresh_token' in token: newToken = Sec.OAuth2Token(provider, token['token_type'], token['access_token'], token['refresh_token'], token['expires_at'], user.id) else: newToken = Sec.OAuth2Token(provider, token['token_type'], token['access_token'], None, token['expires_at'], user.id) db.session.add(newToken) db.session.commit() login_user(user) runWebhook("ZZZ", 20, user=user.username) newLog( 1, "A New User has Registered - Username:"******"An existing OAuth User exists under this email address with another provider", "error") return redirect('/')
def comments_vid_page(videoID): sysSettings = settings.settings.query.first() recordedVid = RecordedVideo.RecordedVideo.query.filter_by( id=videoID).first() if recordedVid is not None: if request.method == 'POST': comment = system.strip_html(request.form['commentText']) currentUser = current_user.id newComment = comments.videoComments(currentUser, comment, recordedVid.id) db.session.add(newComment) db.session.commit() if recordedVid.channel.imageLocation is None: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/static/img/video-placeholder.jpg") else: channelImage = (sysSettings.siteProtocol + sysSettings.siteAddress + "/images/" + recordedVid.channel.imageLocation) pictureLocation = "" if current_user.pictureLocation is None: pictureLocation = '/static/img/user2.png' else: pictureLocation = '/images/' + pictureLocation newNotification = notifications.userNotification( templateFilters.get_userName(current_user.id) + " commented on your video - " + recordedVid.channelName, '/play/' + str(recordedVid.id), "/images/" + str(current_user.pictureLocation), recordedVid.owningUser) db.session.add(newNotification) db.session.commit() webhookFunc.runWebhook( recordedVid.channel.id, 7, channelname=recordedVid.channel.channelName, channelurl=(sysSettings.siteProtocol + sysSettings.siteAddress + "/channel/" + str(recordedVid.channel.id)), channeltopic=templateFilters.get_topicName( recordedVid.channel.topic), channelimage=channelImage, streamer=templateFilters.get_userName( recordedVid.channel.owningUser), channeldescription=str(recordedVid.channel.description), videoname=recordedVid.channelName, videodate=recordedVid.videoDate, videodescription=recordedVid.description, videotopic=templateFilters.get_topicName(recordedVid.topic), videourl=(sysSettings.siteProtocol + sysSettings.siteAddress + '/videos/' + recordedVid.videoLocation), videothumbnail=(sysSettings.siteProtocol + sysSettings.siteAddress + '/videos/' + recordedVid.thumbnailLocation), user=current_user.username, userpicture=(sysSettings.siteProtocol + sysSettings.siteAddress + str(pictureLocation)), comment=comment) flash('Comment Added', "success") system.newLog( 4, "Video Comment Added by " + current_user.username + "to Video ID #" + str(recordedVid.id)) elif request.method == 'GET': if request.args.get('action') == "delete": commentID = int(request.args.get('commentID')) commentQuery = comments.videoComments.query.filter_by( id=commentID).first() if commentQuery is not None: if current_user.has_role( 'Admin' ) or recordedVid.owningUser == current_user.id or commentQuery.userID == current_user.id: upvoteQuery = upvotes.commentUpvotes.query.filter_by( commentID=commentQuery.id).all() for vote in upvoteQuery: db.session.delete(vote) db.session.delete(commentQuery) db.session.commit() system.newLog( 4, "Video Comment Deleted by " + current_user.username + "to Video ID #" + str(recordedVid.id)) flash('Comment Deleted', "success") else: flash("Not Authorized to Remove Comment", "error") else: flash('Invalid Video ID', 'error') return redirect(url_for('root.main_page')) return redirect(url_for('.view_vid_page', videoID=videoID))