Skip to content

Commit

Permalink
Updated to 5.31
Browse files Browse the repository at this point in the history
  • Loading branch information
martastain committed Apr 3, 2021
1 parent 26253fb commit 1aec752
Show file tree
Hide file tree
Showing 12 changed files with 769 additions and 100 deletions.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
install:
cp firefly.desktop ~/.local/share/applications/firefly.desktop
echo 'Path=$(CURDIR)' >> ~/.local/share/applications/firefly.desktop
echo 'Icon=$(CURDIR)/images/icon.png' >> ~/.local/share/applications/firefly.desktop
52 changes: 3 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Firefly
Firefly is a desktop client application for [Nebula](https://github.com/nebulabroadcast/nebula) broadcast automation system.



Installation
------------

Expand Down Expand Up @@ -41,61 +40,16 @@ Edit **settings.json** file to set your server address and site name.
}
```

It is possible to specify more than one site in the settings.json file.
It is possible to specify more than one site in the `settings.json` file.
In that case, a dialog window pops up when the application is started and a site may be selected for this session.

`site_name` argument can be used as an indentifier for different configurations of the same site and its value
`site_name` argument can be used as an identifier for different configurations of the same site and its value
is updated when server settings are loaded.

Usage
-----

### Keyboard shortcuts

Shortcut | Scope | Description
---------------|------------|-----------------------------
ESC | Global | Focus browser search
F1 | Global | Switch to rundown, go to now
F2 | Global | Toggle asset detail
F5 | Global | Refresh views
Ctrl+T | Global | Open new browser tab
Ctrl+W | Global | Close current browser tab
Ctrl+PgUp | Global | Switch to previous tab
Ctrl+PgDown | Global | Switch to next tab
Ctrl+N | Global | Create new asset
Ctrl+Shift+N | Global | Clone current asset
Alt+Left | Scheduler | Previous week
Alt+Right | Scheduler | Next week
Alt+Left | Rundown | Previous day
Alt+Right | Rundown | Next day
Ctrl+D | Rundown | Show calendar
Ctrl+F | Rundown | Search in rundown
Ctrl+R | Rundown | Toggle rundown edit mode
F3 | Rundown | Search in rundown again
Ctrl+J | MCR | Cue previous item
Ctrl+K | MCR | Take
Ctrl+L | MCR | Cue next item
Alt+J | MCR | Retake
Alt+K | MCR | Freeze
Alt+L | MCR | Abort
1, J | Preview | Seek previous 5 frames
2, L | Preview | Seek next 5 frames
3, Left | Preview | Seek previous frame
4, Right | Preview | Seek next frame
A, Home | Preview | Go to start
S, End | Preview | Go to end
Q | Preview | Go to in
W | Preview | Go to out
E, I | Preview | Mark in
R, O | Preview | Mark out
D | Preview | Clear in
F | Preview | Clear out
Space, K | Preview | Play/pause
Ctrl+S | Detail | Save changes/create asset
Y | Detail | Mark asset as approved
T | Detail | Reset QC state
U | Detail | Mark asset as rejected

[Introduction to Firefly](https://nebulabroadcast.com/doc/nebula/firefly-intro.html)

### Troubleshooting

Expand Down
8 changes: 8 additions & 0 deletions firefly.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=Nebula Firefly
Comment=Nebula broadcast automation system client
Exec=./firefly.py
Terminal=false
Categories=Multimedia
2 changes: 1 addition & 1 deletion firefly.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
try:
import rex
except ImportError:
# Freezed application does not need package manager
# Frozen application does not need package manager
pass

from nxtools import *
Expand Down
16 changes: 8 additions & 8 deletions firefly/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ def __init__(self, packet):
self.timestamp, self.site_name, self.host, self.method, self.data = packet

class SeismicListener(QThread):
def __init__(self, site_name, addr, port):
def __init__(self):
QThread.__init__(self, None)
self.site_name = site_name
self.site_name = config["site_name"]
self.should_run = True
self.active = False
self.last_msg = time.time()
Expand All @@ -41,7 +41,7 @@ def __init__(self, site_name, addr, port):
def run(self):
addr = config["hub"].replace("http", "ws", 1) + "/ws/" + config["site_name"]
while self.should_run:
logging.debug("Connecting listener {}".format(addr), handlers=False)
logging.debug(f"[LISTENER] Connecting to {addr}", handlers=False)
self.halted = False
self.ws = websocket.WebSocketApp(
addr,
Expand All @@ -52,21 +52,21 @@ def run(self):
self.ws.run_forever()
self.active = False

logging.debug("Listener halted", handlers=False)
logging.debug("[LISTENER] halted", handlers=False)
self.halted = True


def on_message(self, *args):
data = args[-1]

if not self.active:
logging.goodnews("Listener connected", handlers=False)
logging.goodnews("[LISTENER] connected", handlers=False)
self.active = True
try:
message = SeismicMessage(json.loads(data))
except Exception:
log_traceback(handlers=False)
logging.debug("Malformed seismic message detected: {}".format(data), handlers=False)
logging.debug("[LISTENER] Malformed message: {}".format(data), handlers=False)
return

if message.site_name != self.site_name:
Expand All @@ -86,9 +86,9 @@ def on_error(self, *args):
def on_close(self, *args):
self.active = False
if self.should_run:
logging.warning("WS connection interrupted", handlers=False)
logging.warning("[LISTENER] connection interrupted", handlers=False)

def halt(self):
logging.debug("Shutting down listener")
logging.debug("[LISTENER] Shutting down")
self.should_run = False
self.ws.close()
8 changes: 2 additions & 6 deletions firefly/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,11 @@ def __init__(self, parent, MainWidgetClass):
title = "Firefly {}".format(FIREFLY_VERSION)
if FIREFLY_STATUS:
title += " " + FIREFLY_STATUS
title += " ({}@{})".format(user["login"], config["site_name"])
title += f" ({user['login']}@{config['site_name']})"
self.setWindowTitle(title)
self.setAttribute(Qt.WA_AlwaysShowToolTips)
logging.handlers = [self.log_handler]
self.listener = SeismicListener(
config["site_name"],
config["seismic_addr"],
int(config["seismic_port"])
)
self.listener = SeismicListener()

self.seismic_timer = QTimer(self)
self.seismic_timer.timeout.connect(self.on_seismic_timer)
Expand Down
17 changes: 5 additions & 12 deletions firefly/modules/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,28 +315,21 @@ def contextMenuEvent(self, event):
menu = QMenu(self)
objs = self.view.selected_objects

statuses = []
for obj in objs:
status = obj["status"]
if not status in statuses:
statuses.append(status)
allstat = -1
if len(statuses) == 1:
allstat = statuses[0]

if allstat == TRASHED:
states = set([obj["status"] for obj in objs])

if states == set([TRASHED]):
action_untrash = QAction('Untrash', self)
action_untrash.setStatusTip('Take selected asset(s) from trash')
action_untrash.triggered.connect(self.on_untrash)
menu.addAction(action_untrash)

elif allstat == ARCHIVED:
if states == set([ARCHIVED]):
action_unarchive = QAction('Unarchive', self)
action_unarchive.setStatusTip('Take selected asset(s) from archive')
action_unarchive.triggered.connect(self.on_unarchive)
menu.addAction(action_unarchive)

elif allstat in [ONLINE, CREATING, OFFLINE]:
elif states.issubset([ONLINE, CREATING, OFFLINE]):
action_move_to_trash = QAction('Move to trash', self)
action_move_to_trash.setStatusTip('Move selected asset(s) to trash')
action_move_to_trash.triggered.connect(self.on_trash)
Expand Down
56 changes: 41 additions & 15 deletions firefly/modules/rundown_mcr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

from firefly import *

PROGRESS_BAR_RESOLUTION = 2000
PROGRESS_BAR_RESOLUTION = 1000

class MCRButton(QPushButton):
def __init__(self, title, parent=None, on_click=False):
def __init__(self, title, parent=None, on_click=False, checkable=False):
super(MCRButton, self).__init__(parent)
self.setText(title)
self.setCheckable(checkable)
if title == "Freeze":
bg_col = "#941010"
self.setToolTip("Pause/unpause current clip")
Expand All @@ -26,6 +27,10 @@ def __init__(self, title, parent=None, on_click=False):
text-transform: uppercase;
}}

MCRButton:checked {{
border: 2px solid #00a5c3;
}}

MCRButton:pressed {{
border: 2px solid #00a5c3;
}}""".format(bg_col))
Expand Down Expand Up @@ -81,6 +86,7 @@ def __init__(self, parent):
self.btn_freeze = MCRButton("Freeze", self, self.on_freeze)
self.btn_retake = MCRButton("Retake", self, self.on_retake)
self.btn_abort = MCRButton("Abort", self, self.on_abort)
self.btn_loop = MCRButton("Loop", self, self.on_loop, checkable=True)
self.btn_cue_backward = MCRButton("<", self, self.on_cue_backward)
self.btn_cue_forward = MCRButton(">", self, self.on_cue_forward)

Expand All @@ -106,6 +112,7 @@ def __init__(self, parent):
btns_layout.addWidget(self.btn_freeze ,0)
btns_layout.addWidget(self.btn_retake,0)
btns_layout.addWidget(self.btn_abort,0)
btns_layout.addWidget(self.btn_loop,0)
btns_layout.addWidget(self.btn_cue_backward,0)
btns_layout.addWidget(self.btn_cue_forward,0)
btns_layout.addStretch(1)
Expand Down Expand Up @@ -160,6 +167,9 @@ def on_retake(self):
def on_abort(self):
api.playout(timeout=1, action="abort", id_channel=self.id_channel)

def on_loop(self):
api.playout(timeout=1, action="set", id_channel=self.id_channel, key="loop", value=self.btn_loop.isChecked())

def on_cue_forward(self):
api.playout(timeout=1, action="cue_forward", id_channel=self.id_channel)

Expand All @@ -169,17 +179,31 @@ def on_cue_backward(self):

def seismic_handler(self, data):
status = data.data
self.pos = status["position"] + (1/self.fps)
if status["fps"] != self.fps:
self.fps = status["fps"]

if status.get("time_unit", "f") == "f":
self.pos = (status["position"] + 1) / self.fps
dur = status["duration"] / self.fps
else:
self.pos = status["position"] + (1/self.fps)
dur = status["duration"]

if status.get("loop") != None: #TODO: remove this condition in 5.4 as it should be always present
self.btn_loop.setEnabled(True)
if status.get("loop") != self.btn_loop.isChecked():
print ("Loop", status.get("loop"))
self.btn_loop.setChecked(status.get("loop"))
else:
self.btn_loop.setEnabled(False)

self.request_time = status["request_time"]
self.paused = status["paused"]
self.local_request_time = time.time()

if status["fps"] != self.fps:
self.fps = status["fps"]

if self.dur != status["duration"] or self.first_update:
self.dur = status["duration"]
self.display_dur.set_text(f2tc(self.dur, self.fps))
if self.dur != dur or self.first_update:
self.dur = dur
self.display_dur.set_text(s2tc(self.dur, self.fps))
self.request_display_resize = True
self.first_update = False

Expand Down Expand Up @@ -224,15 +248,15 @@ def update_display(self):
rpos = self.pos

if not self.paused:
rpos += adv * self.fps
rpos += adv

clock = time.strftime("%H:%M:%S:{:02d}", time.localtime(rtime)).format(int(25*(rtime-math.floor(rtime))))
clock = time.strftime("%H:%M:%S:{:02d}", time.localtime(rtime)).format(int(self.fps*(rtime-math.floor(rtime))))
self.display_clock.set_text(clock)
self.display_pos.set_text(f2tc(min(self.dur, rpos), self.fps))
self.display_pos.set_text(s2tc(min(self.dur, rpos), self.fps))

rem = self.dur - rpos
t = f2tc(max(0, rem), self.fps)
if rem < 250:
t = s2tc(max(0, rem), self.fps)
if rem < 10:
self.display_rem.set_text("<font color='red'>{}</font>".format(t))
else:
self.display_rem.set_text(t)
Expand All @@ -246,8 +270,10 @@ def update_display(self):
return
else:
oldval = self.progress_bar.value()
if ppos > oldval or abs(oldval-ppos) > (PROGRESS_BAR_RESOLUTION/self.dur)*self.fps:
if ppos > oldval or abs(oldval-ppos) > PROGRESS_BAR_RESOLUTION/self.dur:
self.progress_bar.setValue(ppos)
self.progress_bar.update()


if self.request_display_resize:
QApplication.processEvents()
Expand Down
4 changes: 2 additions & 2 deletions firefly/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FIREFLY_VERSION = 5.31
#FIREFLY_STATUS = "BETA 5"
FIREFLY_VERSION = 5.32
#FIREFLY_STATUS = "RC1"
FIREFLY_STATUS = ""
10 changes: 9 additions & 1 deletion firefly/widgets/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ def __init__(self, parent, **kwargs):
self.setFocusPolicy(Qt.StrongFocus)
self.setMinimum(kwargs.get("min", 0))
self.setMaximum(kwargs.get("max", 99999))
#TODO: set step to 1. disallow floats
if kwargs.get("hide_null"):
logging.info("HIDE NULL")
self.setMinimum(0)
self.setSpecialValueText(" ")
self.setSingleStep(1)
self.default = self.get_value()

def wheelEvent(self, event):
Expand All @@ -74,6 +78,10 @@ def __init__(self, parent, **kwargs):
self.setFocusPolicy(Qt.StrongFocus)
self.setMinimum(kwargs.get("min", -99999))
self.setMaximum(kwargs.get("max", 99999))
if kwargs.get("hide_null"):
logging.info("HIDE NULL")
self.setMinimum(0)
self.setSpecialValueText(" ")
#TODO: custom step (default 1, allow floats)
self.default = self.get_value()

Expand Down
Loading

0 comments on commit 1aec752

Please sign in to comment.