This commit is contained in:
Your Name 2024-12-02 02:35:49 +05:00
commit d1c12a08b0
7 changed files with 348 additions and 0 deletions

Binary file not shown.

7
docker-compose.yml Normal file
View File

@ -0,0 +1,7 @@
services:
python:
volumes:
- './:/usr/src/app'
working_dir: /usr/src/app
build: .
command: python server.py

10
dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD [ "python", "./server.py" ]

173
index.html Normal file
View File

@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body{
padding:0;
margin:0;
background-repeat: no-repeat;
background-size:contain;
background-position: center;
height: 100vh;
background-color: #4b444b;
}
@media (height < 700px) {
body {
height: 88vh;
}
}
#top_bar {
background-color: #6e84a3;
color: white;
font: bold 24px Helvetica;
padding: 6px 5px 4px 5px;
border-bottom: 1px outset;
}
#status {
text-align: center;
}
</style>
<script>
function createCookie(name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toGMTString();
}
else var expires = "";
document.cookie = name + "=" + value + expires + "; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name, "", -1);
}
function readQueryVariable(name, defaultValue) {
// A URL with a query parameter can look like this:
// https://www.example.com?myqueryparam=myvalue
//
// Note that we use location.href instead of location.search
// because Firefox < 53 has a bug w.r.t location.search
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
match = document.location.href.match(re);
if (match) {
// We have to decode the URL since want the cleartext value
return decodeURIComponent(match[1]);
}
return defaultValue;
}
function uuidv4() {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
(+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
);
}
let uuid = readCookie("uuid")
if (uuid==null){
uuid = uuidv4();
createCookie("uuid",uuid)
}
function status(text) {
document.getElementById('status').textContent = text;
}
window.onload = () => {
if ('WebSocket' in window) {
let was_connect = false;
// create websocket connection
let ws = null;
con()
function con(){
ws = new WebSocket('wss://ws.n0r.su/');
ws.onopen = () => {
console.log('websocket success---');
get()
}
ws.onclose = (e) => {
no_stream();
setTimeout(()=>{con()},5000)
};
ws.onerror = (e) => {
setTimeout(()=>{con()},5000)
no_stream();
// console.error('websocket fail');
}
}
function get() {
ws.send(`get_stream%uuid=${uuid}`);
// setTimeout(() => {
// get();
// }, 100);
ws.onmessage = (message) => {
if (message.data != "null"){
was_connect = true;
let data = message.data;
// console.log('get websocket message---', JSON.parse(data)[1]);
document.body.style.backgroundImage = `url(data:image/jpeg;base64,${JSON.parse(data)[1]})`;
document.getElementById("top_bar").setAttribute("hidden","");
status("conected")
setTimeout(()=>{get()},200)
}
else{
setTimeout(()=>{get();},5000)
no_stream();
}
}
}
ws.onerror = (e) => {
setTimeout(()=>{con()},5000)
no_stream();
// console.error('websocket fail');
}
ws.onclose = (e) => {
setTimeout(()=>{con()},5000)
no_stream()
// console.log("The connection has been closed successfully.")
};
function no_stream(){
if (document.body.style.backgroundImage != `url(/papi/savehouse/?const=club_dance)`){
document.body.style.backgroundImage = `url(/papi/savehouse/?const=club_dance)`;
}
document.getElementById("top_bar").removeAttribute("hidden");
if(was_connect){
status("Stream has ended")
}
else{
status("Stream is closed")
}
}
} else {
console.error('dont support websocket');
};
};
</script>
</head>
<body>
<div id="top_bar">
<div id="status">Loading</div>
</div>
</body>
</html>

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
flask
websockets
pillow

60
screen.py Normal file
View File

@ -0,0 +1,60 @@
#Copyright (C) 2021 Qijun Gu
#
#This file is part of Screenshare.
#
#Screenshare 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.
#
#Screenshare 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 Screenshare. If not, see <https://www.gnu.org/licenses/>.
import threading, time, base64, sys
ver = sys.version_info.major
if ver==2:
import StringIO as io
elif ver==3:
import io
from PIL import ImageGrab as ig
class Screen():
def __init__(self):
self.FPS = 30
self.screenbuf = ""
self.password = ""
if ver==2:
self.screenfile = io.StringIO()
elif ver==3:
self.screenfile = io.BytesIO()
threading.Thread(target=self.getframes).start()
def __del__(self):
self.screenfile.close()
def getframes(self):
while True:
im = ig.grab(bbox=(0, 0, 1920, 1080), include_layered_windows=False, all_screens=False, xdisplay=":0")
self.screenfile.seek(0)
self.screenfile.truncate(0)
im_converted = im.convert("RGB")
im_converted.save(self.screenfile, format="jpeg", quality=60, progressive=True)
self.screenbuf = base64.b64encode(self.screenfile.getvalue())
time.sleep(1.0/self.FPS)
def gen(self):
s = ''
if ver==2:
s = self.screenbuf
elif ver==3:
s = self.screenbuf.decode()
return s
screenlive = Screen()

95
server.py Normal file
View File

@ -0,0 +1,95 @@
from screen import screenlive
import json, argparse
from flask import Flask, json
import threading
from time import sleep
from websockets.sync.server import serve
import websockets
import array
import time
api = Flask(__name__)
watchers_last_seen = {}
stream = False
debug = False
def current_time():
return str(int(time.time()))
@api.route("/off", methods=["GET"])
def streaOff():
global stream
stream=False
return "True"
@api.route("/on", methods=["GET"])
def streamOn():
global stream
stream=True
return "True"
@api.route("/views", methods=["GET"])
def views():
global watchers_last_seen
return str(len(watchers_last_seen))
def ws_server(websocket):
global stream, watchers_last_seen
if debug: print("WebSocket: Server Started.")
try:
while True:
req=websocket.recv()
if "%" in req:
args= req.split("%")[1]
args = dict(x.split("=") for x in args.split(";"))
req = req.split("%")[0]
if debug: print(req,"-----",args)
match (req):
case ("get_stream"):
if stream:
watchers_last_seen[args["uuid"]] = current_time()
websocket.send(f""+str(json.dumps([True, screenlive.gen()])))
else:
websocket.send(f"null")
case (_):
websocket.send(f"null")
except websockets.exceptions.ConnectionClosedOK:
if debug: print("hungup")
except websockets.ConnectionClosedError:
if debug: print("Internal Server Error.")
def run_ws_server():
with serve(ws_server, "0.0.0.0", 7890) as server:
server.serve_forever()
def timeout_task():
while True:
for key,value in watchers_last_seen.items():
if debug: print(key+"||||"+value)
if (int(current_time())-int(value)) > 5:
if debug: print(key+"is timed out")
watchers_last_seen.pop(key)
break
if debug: print("time -",current_time())
if debug: print("watchers -",watchers_last_seen.keys())
sleep(10)
def run_flask_server():
api.run()
def main():
t1 = threading.Thread(target=run_ws_server)
t2 = threading.Thread(target=run_flask_server)
t3 = threading.Thread(target=timeout_task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
if __name__ == "__main__":
main()