Skip to content

Commit

Permalink
use python 3.6 typing
Browse files Browse the repository at this point in the history
all variables and functions are typed in order to help with refactoring
fix mre#31
  • Loading branch information
orcutt989 committed Jan 10, 2020
1 parent 2d411b9 commit 9f056b2
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 63 deletions.
80 changes: 40 additions & 40 deletions timelapse/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,55 @@
from Foundation import NSUserDefaults


def dark_mode():
def dark_mode() -> Any:
return NSUserDefaults.standardUserDefaults().stringForKey_('AppleInterfaceStyle') == "Dark"


# Configuration
start_recording = False # Start recording on launch
encode = True # Create video after recording
screenshot_interval = 1.5 # Number of seconds between screenshots
dir_base = os.path.expanduser("~") # Base directory
dir_app = "timelapse" # Output directory
dir_pictures = "Pictures" # Place for pictures in filesystem
dir_movies = "Movies" # Place for movies in filesystem
dir_resources = "./resources/"
start_recording: bool = False # Start recording on launch
encode: bool = True # Create video after recording
screenshot_interval: float = 1.5 # Number of seconds between screenshots
dir_base: str = os.path.expanduser("~") # Base directory
dir_app: str = "timelapse" # Output directory
dir_pictures: str = "Pictures" # Place for pictures in filesystem
dir_movies: str = "Movies" # Place for movies in filesystem
dir_resources: str = "./resources/"
if dark_mode():
dir_resources += "white"
dir_resources: str += "white"
else:
dir_resources += "black"
dir_resources: str += "black"

subdir_suffix = "Session-" + time.strftime("%Y%m%d") # Name of subdirectory
image_recording = "record.gif" # App icon recording
image_idle = "stop.gif" # App icon idle
create_session_subdir = True # New screenshot directory for each session
create_movies = True # Create movies from screenshots after recording
subdir_suffix: str = "Session-" + time.strftime("%Y%m%d") # Name of subdirectory
image_recording: str = "record.gif" # App icon recording
image_idle: str = "stop.gif" # App icon idle
create_session_subdir: str = True # New screenshot directory for each session
create_movies: bool = True # Create movies from screenshots after recording
# Menu item text when recorder is running
text_recorder_running = "Stop recording"
text_recorder_idle = "Start recording" # Menu item text when recorder is idle
text_recorder_running: str = "Stop recording"
text_recorder_idle: str = "Start recording" # Menu item text when recorder is idle
# Tooltip of menu icon when not recording
tooltip_idle = "Timelapse screen recorder"
tooltip_running = "Recording | " + tooltip_idle # Tooltip when recording
tooltip_idle: str = "Timelapse screen recorder"
tooltip_running: str = "Recording | " + tooltip_idle # Tooltip when recording


###############

class Timelapse(NSObject):
""" Creates a timelapse video """

def applicationDidFinishLaunching_(self, notification):
def applicationDidFinishLaunching_(self, notification) -> None:
self.check_dependencies()

# Initialize recording
self.recording = start_recording
self.recording: bool = start_recording
self.recorder = None

# Set correct output paths
self.recorder_output_basedir = os.path.join(
self.recorder_output_basedir: str = os.path.join(
dir_base, dir_pictures, dir_app)
self.encoder_output_basedir = os.path.join(dir_base, dir_movies)
self.encoder_output_basedir: str = os.path.join(dir_base, dir_movies)

self.image_dir = self.create_dir(self.recorder_output_basedir)
self.image_dir: str = self.create_dir(self.recorder_output_basedir)

# Create a reference to the statusbar (menubar)
self.statusbar = NSStatusBar.systemStatusBar()
Expand All @@ -77,13 +77,13 @@ def applicationDidFinishLaunching_(self, notification):
self.loadIcons()
self.setStatus()

def loadIcons(self):
def loadIcons(self) -> None:
self.icon_recording = NSImage.alloc().initWithContentsOfFile_(
os.path.join(dir_resources, image_recording))
self.icon_idle = NSImage.alloc().initWithContentsOfFile_(
os.path.join(dir_resources, image_idle))

def setStatus(self):
def setStatus(self) -> None:
""" Sets the image and menu text according to recording status """
if self.recording:
self.statusitem.setImage_(self.icon_recording)
Expand All @@ -94,7 +94,7 @@ def setStatus(self):
self.recordButton.setTitle_(text_recorder_idle)
self.statusitem.setToolTip_(tooltip_idle)

def createMenu(self):
def createMenu(self) -> menu:
""" Status bar menu """
menu = NSMenu.alloc().init()
# Bind record event
Expand All @@ -107,7 +107,7 @@ def createMenu(self):
menu.addItem_(menuitem)
return menu

def startStopRecording_(self, notification):
def startStopRecording_(self, notification) -> None:
if self.recording:
self.recorder.join(timeout=screenshot_interval*2)
# Create timelapse after recording?
Expand All @@ -119,18 +119,18 @@ def startStopRecording_(self, notification):
notify("Timelapse started", "The recording has started")
self.recorder = Recorder(self.image_dir, screenshot_interval)
self.recorder.start()
self.recording = not self.recording
self.recording: bool = not self.recording
self.setStatus()

@objc.python_method
def create_dir(self, base_dir):
def create_dir(self, base_dir: str) -> str:
""" Creates a specified directory and the path to it if necessary """
if create_session_subdir:
# Create a new subdirectory
output_dir = os.path.join(base_dir, self.get_sub_dir(base_dir))
output_dir: str = os.path.join(base_dir, self.get_sub_dir(base_dir))
else:
# Don't create a subdirectory. Use base directory for output
output_dir = base_dir
output_dir: str = base_dir
# Create path if it doesn't exist
try:
print(f"Output directory: {output_dir}")
Expand All @@ -144,20 +144,20 @@ def create_dir(self, base_dir):
return output_dir

@objc.python_method
def get_sub_dir(self, base_dir):
def get_sub_dir(self, base_dir) -> str:
""" Returns the next nonexistend subdirectory to base_dir """
subdir_base = os.path.join(base_dir, subdir_suffix)
subdir_base: str = os.path.join(base_dir, subdir_suffix)
# Check if we can use subdir without any session id
subdir = subdir_base
subdir: str = subdir_base
# Use a session id only if subdir already exists
session_number = 0
session_number: int = 0
while os.path.exists(subdir):
# We can't use subdir. Create directory with session id
session_number += 1
subdir = subdir_base + "-" + str(session_number)
session_number: int += 1
subdir: str = subdir_base + "-" + str(session_number)
return subdir

def check_dependencies(self):
def check_dependencies(self) -> None:
try:
subprocess.run(['ffmpeg'], check=True,
capture_output=True, timeout=10.0)
Expand Down
14 changes: 7 additions & 7 deletions timelapse/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@
class Encoder(Thread):
"""Create a video file from images"""

def __init__(self, input_dir, output_dir):
def __init__(self, input_dir: str, output_dir: str) -> None:
# Initialize the thread
Thread.__init__(self)

# Set config options
self.input = f"{input_dir}/%d.png"
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
self.output = f"{output_dir}/timelapse-{timestamp}.mov"
self.input: str = f"{input_dir}/%d.png"
timestamp: str = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
self.output: str = f"{output_dir}/timelapse-{timestamp}.mov"

print("Encoder started")

def join(self, timeout=None):
def join(self, timeout=None) -> None:
""" Hard shutdown """
Thread.join(self)

def run(self):
def run(self) -> None:
"""
Now that we have screenshots of the user's desktop, we will stitch them
together using `ffmpeg` to create a movie. Each image will become
a single frame in the movie.
"""
# Call ffmpeg with settings compatible with QuickTime.
# https://superuser.com/a/820137
command = ["/usr/local/bin/ffmpeg", "-y",
command: List[int] = ["/usr/local/bin/ffmpeg", "-y",
"-framerate", "30",
"-i", self.input,
"-vf", "format=yuv420p",
Expand Down
2 changes: 1 addition & 1 deletion timelapse/notify.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os


def notify(title, text):
def notify(title: str, text: str) -> None:
os.system("""
osascript -e 'display notification "{}" with title "{}"'
""".format(text, title))
30 changes: 15 additions & 15 deletions timelapse/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from AppKit import NSEvent, NSScreen, NSMouseInRect


def get_screen_with_mouse_index():
def get_screen_with_mouse_index() ->int:
mouseLocation = NSEvent.mouseLocation()
screens = NSScreen.screens()
for i, screen in enumerate(screens):
Expand All @@ -20,7 +20,7 @@ class Recorder(Process):
Takes a screenshot every 'interval' seconds and saves it into output_dir or a subdirectory thereof.
"""

def __init__(self, output_dir, interval=4):
def __init__(self, output_dir: str, interval: int=4) -> None:
# Initialize the thread
Process.__init__(self)

Expand All @@ -29,44 +29,44 @@ def __init__(self, output_dir, interval=4):
self._stopped = Event()

# Set config options
self.output_dir = output_dir
self.interval = interval
self.format = "png"
self.output_dir: str = output_dir
self.interval: int = interval
self.format: str = "png"

# Number of screenshots taken
self.screenshot_counter = 0
self.screenshot_counter: int = 0
print("Recorder started")

def join(self, timeout=None):
def join(self, timeout=None) -> None:
""" Stop recording """
self._stop.set()
self._stopped.wait()
print("Recorder stopped. Total recording time: " +
self.get_recording_time() + ".")
Process.join(self, timeout=timeout)

def run(self):
def run(self) -> None:
""" Periodically take a screenshots of the screen """
while not self._stop.is_set():
self.screenshot()
self._stop.wait(self.interval)

self._stopped.set()

def get_recording_time(self):
def get_recording_time(self) ->str:
return str(self.screenshot_counter * self.interval) + " seconds"

def get_filename(self):
def get_filename(self) ->str:
""" Call screencapture for mac screenshot """
filename = os.path.join(
filename: str = os.path.join(
self.output_dir, f"{self.screenshot_counter}.{self.format}")
return filename

def screenshot(self):
def screenshot(self) -> None:
""" This method uses Mac OSX screencapture from the commandline """
filename = self.get_filename()
filename: str = self.get_filename()
subprocess.run(
['screencapture', '-S', '-o', '-x', '-D',
str(get_screen_with_mouse_index() + 1), '-t', self.format, filename],
check=True)
self.screenshot_counter += 1
check: bool =True)
self.screenshot_counter: int += 1

0 comments on commit 9f056b2

Please sign in to comment.