Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
S
SHMCamStudio
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
SexHackMe
SHMCamStudio
Commits
8853586d
Commit
8853586d
authored
Nov 10, 2024
by
nextime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Really revert the changes
parent
0a5b7c4e
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
204 additions
and
46 deletions
+204
-46
shmcamstudio
shmcamstudio
+204
-46
No files found.
shmcamstudio
View file @
8853586d
...
@@ -33,15 +33,15 @@ import vlc
...
@@ -33,15 +33,15 @@ import vlc
# Read configuration
# Read configuration
config
=
configparser
.
ConfigParser
()
config
=
configparser
.
ConfigParser
()
config
.
read
(
"config.ini"
)
config
.
read
(
'config.ini'
)
# Setup logging
# Setup logging
log_file
=
config
.
get
(
"General"
,
"log_file"
,
fallback
=
"/tmp/streaming_control.log"
)
log_file
=
config
.
get
(
'General'
,
'log_file'
,
fallback
=
'/tmp/streaming_control.log'
)
log_level
=
config
.
get
(
"General"
,
"log_level"
,
fallback
=
"INFO"
)
log_level
=
config
.
get
(
'General'
,
'log_level'
,
fallback
=
'INFO'
)
logging
.
basicConfig
(
logging
.
basicConfig
(
level
=
getattr
(
logging
,
log_level
),
level
=
getattr
(
logging
,
log_level
),
format
=
"
%(asctime)
s -
%(levelname)
s -
%(message)
s"
,
format
=
'
%(asctime)
s -
%(levelname)
s -
%(message)
s'
,
handlers
=
[
handlers
=
[
RotatingFileHandler
(
log_file
,
maxBytes
=
1024
*
1024
,
backupCount
=
5
),
RotatingFileHandler
(
log_file
,
maxBytes
=
1024
*
1024
,
backupCount
=
5
),
logging
.
StreamHandler
(
sys
.
stdout
)
logging
.
StreamHandler
(
sys
.
stdout
)
...
@@ -53,7 +53,7 @@ logger = logging.getLogger(__name__)
...
@@ -53,7 +53,7 @@ logger = logging.getLogger(__name__)
flask_app
=
Flask
(
__name__
)
flask_app
=
Flask
(
__name__
)
# Command Mapping
# Command Mapping
COMMANDS
=
dict
(
config
[
"Commands"
])
COMMANDS
=
dict
(
config
[
'Commands'
])
def
run_command
(
command
):
def
run_command
(
command
):
try
:
try
:
...
@@ -65,13 +65,13 @@ def run_command(command):
...
@@ -65,13 +65,13 @@ def run_command(command):
logger
.
error
(
f
"Error executing command {command}: {e}"
)
logger
.
error
(
f
"Error executing command {command}: {e}"
)
return
f
"Error: {e}"
return
f
"Error: {e}"
@
flask_app
.
route
(
"/"
)
@
flask_app
.
route
(
'/'
)
def
index
():
def
index
():
return
render_template
(
"index.html"
,
commands
=
COMMANDS
)
return
render_template
(
'index.html'
,
commands
=
COMMANDS
)
@
flask_app
.
route
(
"/execute"
,
methods
=
[
"POST"
])
@
flask_app
.
route
(
'/execute'
,
methods
=
[
'POST'
])
def
execute
():
def
execute
():
command_key
=
request
.
form
.
get
(
"command"
)
command_key
=
request
.
form
.
get
(
'command'
)
if
command_key
in
COMMANDS
:
if
command_key
in
COMMANDS
:
result
=
run_command
(
COMMANDS
[
command_key
])
result
=
run_command
(
COMMANDS
[
command_key
])
...
@@ -79,13 +79,13 @@ def execute():
...
@@ -79,13 +79,13 @@ def execute():
else
:
else
:
return
"Invalid command"
,
400
return
"Invalid command"
,
400
@
flask_app
.
route
(
"/stream"
)
@
flask_app
.
route
(
'/stream'
)
def
stream
():
def
stream
():
stream_url
=
config
.
get
(
"Web"
,
"stream_url"
,
fallback
=
"https://192.168.42.1/HLS/record/Live.m3u8"
)
stream_url
=
config
.
get
(
'Web'
,
'stream_url'
,
fallback
=
"https://192.168.42.1/HLS/record/Live.m3u8"
)
return
render_template
(
"stream.html"
,
stream_url
=
stream_url
)
return
render_template
(
'stream.html'
,
stream_url
=
stream_url
)
def
create_daemon
():
def
create_daemon
():
if
os
.
name
==
"posix"
:
# Unix-like systems
if
os
.
name
==
'posix'
:
# Unix-like systems
try
:
try
:
# First fork
# First fork
pid
=
os
.
fork
()
pid
=
os
.
fork
()
...
@@ -93,11 +93,11 @@ def create_daemon():
...
@@ -93,11 +93,11 @@ def create_daemon():
# Exit first parent
# Exit first parent
sys
.
exit
(
0
)
sys
.
exit
(
0
)
except
OSError
as
err
:
except
OSError
as
err
:
logger
.
error
(
f
"Fork #1 failed: {err}"
)
logger
.
error
(
f
'Fork #1 failed: {err}'
)
sys
.
exit
(
1
)
sys
.
exit
(
1
)
# Decouple from parent environment
# Decouple from parent environment
os
.
chdir
(
"/"
)
os
.
chdir
(
'/'
)
os
.
setsid
()
os
.
setsid
()
os
.
umask
(
0
)
os
.
umask
(
0
)
...
@@ -108,53 +108,211 @@ def create_daemon():
...
@@ -108,53 +108,211 @@ def create_daemon():
# Exit from second parent
# Exit from second parent
sys
.
exit
(
0
)
sys
.
exit
(
0
)
except
OSError
as
err
:
except
OSError
as
err
:
logger
.
error
(
f
"Fork #2 failed: {err}"
)
logger
.
error
(
f
'Fork #2 failed: {err}'
)
sys
.
exit
(
1
)
sys
.
exit
(
1
)
# Redirect standard file descriptors
# Redirect standard file descriptors
sys
.
stdout
.
flush
()
sys
.
stdout
.
flush
()
sys
.
stderr
.
flush
()
sys
.
stderr
.
flush
()
si
=
open
(
os
.
devnull
,
"r"
)
si
=
open
(
os
.
devnull
,
'r'
)
so
=
open
(
os
.
devnull
,
"a+"
)
so
=
open
(
os
.
devnull
,
'a+'
)
se
=
open
(
os
.
devnull
,
"a+"
)
se
=
open
(
os
.
devnull
,
'a+'
)
os
.
dup2
(
si
.
fileno
(),
sys
.
stdin
.
fileno
())
os
.
dup2
(
si
.
fileno
(),
sys
.
stdin
.
fileno
())
os
.
dup2
(
so
.
fileno
(),
sys
.
stdout
.
fileno
())
os
.
dup2
(
so
.
fileno
(),
sys
.
stdout
.
fileno
())
os
.
dup2
(
se
.
fileno
(),
sys
.
stderr
.
fileno
())
os
.
dup2
(
se
.
fileno
(),
sys
.
stderr
.
fileno
())
elif
os
.
name
==
'nt'
:
# Windows
try
:
# Hide the console window
si
=
subprocess
.
STARTUPINFO
()
si
.
dwFlags
|=
subprocess
.
STARTF_USESHOWWINDOW
# Start the script as a new process
subprocess
.
Popen
([
sys
.
executable
,
__file__
],
startupinfo
=
si
,
creationflags
=
subprocess
.
CREATE_NEW_PROCESS_GROUP
)
# Exit the current process
sys
.
exit
(
0
)
except
Exception
as
err
:
logger
.
error
(
f
'Failed to create background process: {err}'
)
sys
.
exit
(
1
)
else
:
logger
.
error
(
f
'Unsupported operating system: {os.name}'
)
sys
.
exit
(
1
)
def
check_port_available
(
port
):
"""Check if a port is available"""
with
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
as
s
:
return
s
.
connect_ex
((
'localhost'
,
port
))
!=
0
def
run_flask_app
(
port
=
5000
,
daemon_mode
=
False
):
"""Run Flask app with optional daemon mode"""
if
not
check_port_available
(
port
):
logger
.
error
(
f
"Port {port} is already in use"
)
sys
.
exit
(
1
)
logger
.
info
(
f
"Starting Flask app on port {port}"
)
if
daemon_mode
and
sys
.
platform
!=
'win32'
:
create_daemon
()
flask_app
.
run
(
host
=
'0.0.0.0'
,
port
=
port
,
debug
=
False
,
use_reloader
=
False
)
class
VideoPlayer
:
def
__init__
(
self
,
master
,
video_url
):
self
.
master
=
master
# VLC player setup
args
=
[]
_isLinux
=
sys
.
platform
.
startswith
(
'linux'
)
if
_isLinux
:
args
.
append
(
'--vout=mmal_vout'
)
# Create a VLC instance
self
.
Instance
=
vlc
.
Instance
(
args
)
# Create a new MediaPlayer
self
.
player
=
self
.
Instance
.
media_player_new
()
# Set the media
media
=
self
.
Instance
.
media_new
(
video_url
)
self
.
player
.
set_media
(
media
)
# Create a frame for the video
self
.
video_frame
=
self
.
master
self
.
video_frame
.
pack
(
fill
=
tk
.
BOTH
,
expand
=
True
)
self
.
canvas
=
tk
.
Canvas
(
self
.
video_frame
,
width
=
800
)
self
.
canvas
.
pack
(
fill
=
tk
.
BOTH
,
expand
=
True
)
def
create_tkinter_interface
():
# Embed the VLC Video
root
=
tk
.
Tk
()
win_id
=
self
.
canvas
.
winfo_id
()
root
.
title
(
config
.
get
(
"Tkinter"
,
"window_title"
,
fallback
=
"SHM Cam Studio"
))
if
_isLinux
:
root
.
geometry
(
f
"{config.get(Tkinter, window_width, fallback=300)}x{config.get(Tkinter, window_height, fallback=400)}"
)
self
.
player
.
set_xwindow
(
win_id
)
else
:
self
.
player
.
set_hwnd
(
win_id
)
# Play the video
self
.
player
.
play
()
button_font
=
tkFont
.
Font
(
size
=
int
(
config
.
get
(
"Tkinter"
,
"font_size"
,
fallback
=
"12"
)))
button_width
=
int
(
config
.
get
(
"Tkinter"
,
"button_width"
,
fallback
=
"20"
))
button_height
=
int
(
config
.
get
(
"Tkinter"
,
"button_height"
,
fallback
=
"2"
))
for
command_name
,
command
in
COMMANDS
.
items
():
button
=
tk
.
Button
(
root
,
text
=
command_name
,
command
=
lambda
cmd
=
command
:
run_command
(
cmd
),
font
=
button_font
,
width
=
button_width
,
height
=
button_height
)
button
.
pack
(
pady
=
5
)
root
.
mainloop
()
def
create_tkinter_gui
():
# Create the main window
window
=
tk
.
Tk
()
window
.
title
(
"Streaming Control Panel"
)
def
run_flask
():
helv36
=
tkFont
.
Font
(
family
=
'Helvetica'
,
size
=
13
,
weight
=
'bold'
)
port
=
config
.
get
(
"Web"
,
"port"
,
fallback
=
"5000"
)
flask_app
.
run
(
host
=
"0.0.0.0"
,
port
=
int
(
port
))
if
__name__
==
"__main__"
:
# Frame for the left side
parser
=
argparse
.
ArgumentParser
(
description
=
"SHM Cam Studio"
)
fleft
=
tk
.
Frame
(
window
)
parser
.
add_argument
(
"--daemon"
,
action
=
"store_true"
,
help
=
"Run as daemon"
)
fleft
.
pack
(
side
=
tk
.
LEFT
,
fill
=
tk
.
BOTH
,
expand
=
True
)
args
=
parser
.
parse_args
()
if
args
.
daemon
:
# URL of your HLS stream
create_daemon
()
video_url
=
"rtmp://192.168.42.1/record/Live"
VideoPlayer
(
fleft
,
video_url
)
# Frame for the right side
fright
=
tk
.
Frame
(
window
)
fright
.
pack
(
side
=
tk
.
RIGHT
,
fill
=
tk
.
BOTH
,
expand
=
True
)
flask_thread
=
threading
.
Thread
(
target
=
run_flask
)
# Frame for the first two rows in the right frame
flask_thread
.
start
()
frame1
=
tk
.
Frame
(
fright
)
frame1
.
pack
(
fill
=
tk
.
BOTH
,
expand
=
True
)
# Buttons configuration
buttons_row0
=
[
(
'PRIVATE STEFY'
,
'smblur_private_stefy'
),
(
'PRIVATE LEELOO'
,
'smblur_private_leeloo'
),
(
'PRIVATE JASMIN'
,
'smblur_private_jasmin'
),
(
'PRIVATE OTHER'
,
'smblur_private'
)
]
buttons_row1
=
[
(
'OPEN/CLOSE STEFY'
,
'smblur_stefy'
),
(
'OPEN/CLOSE LEELOO'
,
'smblur_leeloo'
),
(
'OPEN/CLOSE JASMIN'
,
'smblur_jasmin'
),
(
'OPEN/CLOSE OTHERS'
,
'smblur_shine'
)
]
# Create buttons for the first two rows
for
j
,
(
text
,
command
)
in
enumerate
(
buttons_row0
):
button
=
tk
.
Button
(
frame1
,
text
=
text
,
font
=
helv36
,
width
=
25
,
height
=
15
,
bg
=
"green"
,
fg
=
"white"
,
command
=
lambda
cmd
=
command
:
run_command
(
cmd
))
button
.
grid
(
row
=
0
,
column
=
j
,
sticky
=
'nsew'
)
for
j
,
(
text
,
command
)
in
enumerate
(
buttons_row1
):
button
=
tk
.
Button
(
frame1
,
text
=
text
,
font
=
helv36
,
width
=
25
,
height
=
15
,
bg
=
"green"
,
fg
=
"white"
,
command
=
lambda
cmd
=
command
:
run_command
(
cmd
))
button
.
grid
(
row
=
1
,
column
=
j
,
sticky
=
'nsew'
)
# Configure the columns in the first frame
for
i
in
range
(
4
):
frame1
.
grid_columnconfigure
(
i
,
weight
=
1
)
# Frame for the third row in the right frame
frame2
=
tk
.
Frame
(
fright
)
frame2
.
pack
(
fill
=
tk
.
BOTH
,
expand
=
True
)
# Row 2 with 3 buttons
buttons_row2
=
[
(
'TEASE'
,
'smblur_tease'
),
(
'TEASE ALL'
,
'smblur_teaseall'
),
(
'OPEN'
,
'smblur_clean'
)
]
# Create buttons for the third row
for
j
,
(
text
,
command
)
in
enumerate
(
buttons_row2
):
button
=
tk
.
Button
(
frame2
,
text
=
text
,
font
=
helv36
,
width
=
30
,
height
=
25
,
bg
=
"blue"
,
fg
=
"white"
,
command
=
lambda
cmd
=
command
:
run_command
(
cmd
))
button
.
grid
(
row
=
0
,
column
=
j
,
sticky
=
'nsew'
)
# Configure the columns in the second frame
for
i
in
range
(
3
):
frame2
.
grid_columnconfigure
(
i
,
weight
=
1
)
# Add a button to open web interface
web_button
=
tk
.
Button
(
frame2
,
text
=
"Open Web Interface"
,
command
=
lambda
:
webbrowser
.
open
(
'http://localhost:5000'
),
bg
=
"purple"
,
fg
=
"white"
,
font
=
helv36
)
web_button
.
grid
(
row
=
1
,
column
=
1
,
sticky
=
'nsew'
)
return
window
def
main
():
# Setup argument parser
parser
=
argparse
.
ArgumentParser
(
description
=
'Streaming Control Panel'
)
parser
.
add_argument
(
'--web-only'
,
action
=
'store_true'
,
help
=
'Start only the web interface'
)
parser
.
add_argument
(
'--daemon'
,
action
=
'store_true'
,
help
=
'Run in daemon mode (Unix-like systems only)'
)
parser
.
add_argument
(
'--port'
,
type
=
int
,
default
=
5000
,
help
=
'Port for the web interface (default: 5000)'
)
# Parse arguments
args
=
parser
.
parse_args
()
try
:
# Daemon mode for web interface
if
args
.
web_only
or
args
.
daemon
:
run_flask_app
(
port
=
args
.
port
,
daemon_mode
=
args
.
daemon
)
else
:
# Start web interface in a background thread
web_thread
=
threading
.
Thread
(
target
=
run_flask_app
,
kwargs
=
{
'port'
:
args
.
port
},
daemon
=
True
)
web_thread
.
start
()
create_tkinter_interface
()
# Launch Tkinter GUI
window
=
create_tkinter_gui
()
window
.
mainloop
()
# Cleanup
except
Exception
as
e
:
flask_thread
.
join
()
logger
.
error
(
f
"Unexpected error: {e}"
)
sys
.
exit
(
1
)
if
__name__
==
'__main__'
:
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment