Added frequency to SSTV filenames, refactored storage code, etc.

This commit is contained in:
Marat Fayzullin 2023-02-28 14:38:24 -05:00
parent 5d97d68f60
commit e1300f76d8
6 changed files with 40 additions and 20 deletions

View File

@ -31,3 +31,9 @@ td {
img { img {
width: 100%; width: 100%;
} }
.file-title {
text-align: center;
font-size: 80%;
}

View File

@ -301,8 +301,9 @@ SstvMessagePanel.prototype.pushMessage = function(msg) {
// $b.scrollTop($b[0].scrollHeight); // $b.scrollTop($b[0].scrollHeight);
} }
else if(msg.width>0 && msg.height>0 && !msg.hasOwnProperty('line')) { else if(msg.width>0 && msg.height>0 && !msg.hasOwnProperty('line')) {
var f = msg.frequency>0? ' at ' + Math.floor(msg.frequency/1000) + 'kHz' : '';
var h = '<div>' + msg.timestamp + ' ' + msg.width + 'x' + msg.height + var h = '<div>' + msg.timestamp + ' ' + msg.width + 'x' + msg.height +
' ' + msg.sstvMode + '</div>'; ' ' + msg.sstvMode + f + '</div>';
var c = '<div onclick="saveCanvas(\'' + msg.filename + '\');">' + var c = '<div onclick="saveCanvas(\'' + msg.filename + '\');">' +
'<canvas class="frame" id="' + msg.filename + '<canvas class="frame" id="' + msg.filename +
'" width="' + msg.width + '" height="' + msg.height + '" width="' + msg.width + '" height="' + msg.height +

View File

@ -4,7 +4,7 @@ from owrx.storage import Storage
class FileController(AssetsController): class FileController(AssetsController):
def getFilePath(self, file): def getFilePath(self, file):
return Storage().getStoredFilePath(file) return Storage().getFilePath(file)
class FilesController(WebpageController): class FilesController(WebpageController):
@ -20,7 +20,7 @@ class FilesController(WebpageController):
rows += ('<td class="file-tile">' + rows += ('<td class="file-tile">' +
('<a href="/files/%s" download="%s">' % (files[i], files[i])) + ('<a href="/files/%s" download="%s">' % (files[i], files[i])) +
('<img src="/files/%s" download="%s">' % (files[i], files[i])) + ('<img src="/files/%s" download="%s">' % (files[i], files[i])) +
('<p align="center">%s</p>' % files[i]) + ('<p class="file-title">%s</p>' % files[i]) +
'</a></td>\n') '</a></td>\n')
# Finish a row # Finish a row
if i % 3 == 2: if i % 3 == 2:

View File

@ -23,6 +23,7 @@ from owrx.controllers.session import SessionController
from owrx.controllers.profile import ProfileController from owrx.controllers.profile import ProfileController
from owrx.controllers.imageupload import ImageUploadController from owrx.controllers.imageupload import ImageUploadController
from owrx.controllers.robots import RobotsController from owrx.controllers.robots import RobotsController
from owrx.storage import Storage
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
import re import re
@ -98,7 +99,7 @@ class Router(object):
StaticRoute("/policy", PolicyController), StaticRoute("/policy", PolicyController),
StaticRoute("/features", FeatureController), StaticRoute("/features", FeatureController),
StaticRoute("/files", FilesController), StaticRoute("/files", FilesController),
RegexRoute("^/files/(SSTV-[0-9]+-[0-9]+\.bmp)$", FileController), RegexRoute("^/files/(%s)$" % Storage().getNamePattern(), FileController),
StaticRoute("/api/features", ApiController), StaticRoute("/api/features", ApiController),
StaticRoute("/metrics", MetricsController, options={"action": "prometheusAction"}), StaticRoute("/metrics", MetricsController, options={"action": "prometheusAction"}),
StaticRoute("/metrics.json", MetricsController), StaticRoute("/metrics.json", MetricsController),

View File

@ -17,7 +17,7 @@ modeNames = {
44: "Martin 1", 44: "Martin 1",
56: "Scottie 2", 56: "Scottie 2",
60: "Scottie 1", 60: "Scottie 1",
76: "Scottie DX", 75: "Scottie DX",
# Unsupported modes # Unsupported modes
0: "Robot 12", 0: "Robot 12",
@ -58,13 +58,14 @@ modeNames = {
class SstvParser(ThreadModule): class SstvParser(ThreadModule):
def __init__(self, service: bool = False): def __init__(self, service: bool = False):
self.service = service self.service = service
self.file = None self.frequency = 0
self.data = bytearray(b'') self.file = None
self.width = 0 self.data = bytearray(b'')
self.height = 0 self.width = 0
self.line = 0 self.height = 0
self.mode = 0 self.line = 0
self.mode = 0
super().__init__() super().__init__()
def __del__(self): def __del__(self):
@ -92,7 +93,7 @@ class SstvParser(ThreadModule):
def newFile(self, fileName): def newFile(self, fileName):
self.closeFile() self.closeFile()
try: try:
self.fileName = Storage().getStoredFilePath(fileName + ".bmp") self.fileName = Storage().getFilePath(fileName + ".bmp")
logger.debug("Opening bitmap file '%s'..." % self.fileName) logger.debug("Opening bitmap file '%s'..." % self.fileName)
self.file = open(self.fileName, "wb") self.file = open(self.fileName, "wb")
except Exception: except Exception:
@ -111,6 +112,9 @@ class SstvParser(ThreadModule):
def getOutputFormat(self) -> Format: def getOutputFormat(self) -> Format:
return Format.CHAR return Format.CHAR
def setDialFrequency(self, frequency: int) -> None:
self.frequency = frequency
def run(self): def run(self):
# Run while there is input data # Run while there is input data
while self.doRun: while self.doRun:
@ -141,9 +145,10 @@ class SstvParser(ThreadModule):
self.mode = self.data[6] self.mode = self.data[6]
self.line = 0 self.line = 0
# Find mode name and time # Find mode name and time
modeName = modeNames.get(self.mode) if self.mode in modeNames else "Unknown Mode" modeName = modeNames.get(self.mode) if self.mode in modeNames else "Unknown Mode %d" % self.mode
timeStamp = datetime.utcnow().strftime("%H:%M:%S") timeStamp = datetime.utcnow().strftime("%H:%M:%S")
fileName = Storage().makeStoredFileName("SSTV-{0}") fileName = Storage().makeFileName("SSTV-{0}", self.frequency)
logger.debug("Receiving %dx%d %s frame as '%s'." % (self.width, self.height, modeName, fileName))
# If running as a service... # If running as a service...
if self.service: if self.service:
# Create a new image file and write BMP header # Create a new image file and write BMP header
@ -158,7 +163,8 @@ class SstvParser(ThreadModule):
"height": self.height, "height": self.height,
"sstvMode": modeName, "sstvMode": modeName,
"timestamp": timeStamp, "timestamp": timeStamp,
"filename": fileName "filename": fileName,
"frequency": self.frequency
} }
# Parse debug messages enclosed in ' [...]' # Parse debug messages enclosed in ' [...]'

View File

@ -11,16 +11,22 @@ logger = logging.getLogger(__name__)
class Storage(object): class Storage(object):
def __init__(self): def __init__(self):
self.filePattern = r'[A-Z]+-[0-9]+-[0-9]+\.bmp' self.filePattern = r'[A-Z]+-[0-9]+-[0-9]+(-[0-9]+)?\.bmp'
# Get file name pattern
def getNamePattern(self):
return self.filePattern
# Create stored file name by inserting current UTC date # Create stored file name by inserting current UTC date
# and time into the pattern spot designated with "{0}" # and time into the pattern spot designated with "{0}"
def makeStoredFileName(self, pattern): def makeFileName(self, pattern: str = '{0}', frequency: int = 0):
return pattern.format(datetime.utcnow().strftime('%y%m%d-%H%M%S')) d = datetime.utcnow().strftime('%y%m%d-%H%M%S')
f = ('-%d' % (frequency // 1000)) if frequency>0 else ''
return pattern.format(d + f)
# Get complete path to a stored file from its filename by # Get complete path to a stored file from its filename by
# adding folder name # adding folder name
def getStoredFilePath(self, filename): def getFilePath(self, filename: str):
return os.path.join(CoreConfig().get_temporary_directory(), filename) return os.path.join(CoreConfig().get_temporary_directory(), filename)
# Get list of stored files, sorted in reverse alphabetic order # Get list of stored files, sorted in reverse alphabetic order