) => void
+}) => {
+ return (
+
+
+
+
+ )
+}
diff --git a/static/src/store/settings/index.ts b/static/src/store/settings/index.ts
index ee97c67e4..33935012d 100644
--- a/static/src/store/settings/index.ts
+++ b/static/src/store/settings/index.ts
@@ -35,6 +35,7 @@ export const fetchSettings = createAsyncThunk(
shufflePlaylist: data.shuffle_playlist || false,
use24HourClock: data.use_24_hour_clock || false,
debugLogging: data.debug_logging || false,
+ rotateDisplay: data.rotate_display || 0,
}
} catch (error) {
return rejectWithValue((error as Error).message)
@@ -76,6 +77,7 @@ export const updateSettings = createAsyncThunk(
shuffle_playlist: settings.shufflePlaylist,
use_24_hour_clock: settings.use24HourClock,
debug_logging: settings.debugLogging,
+ rotate_display: settings.rotateDisplay,
}),
})
@@ -176,6 +178,7 @@ const initialState = {
shufflePlaylist: false,
use24HourClock: false,
debugLogging: false,
+ rotateDisplay: 0,
},
deviceModel: '',
prevAuthBackend: '',
diff --git a/static/src/tests/settings.test.tsx b/static/src/tests/settings.test.tsx
index 5313aceb9..fe54d66de 100644
--- a/static/src/tests/settings.test.tsx
+++ b/static/src/tests/settings.test.tsx
@@ -45,6 +45,7 @@ const createMockStore = (preloadedState: Partial = {}) => {
shufflePlaylist: true,
use24HourClock: false,
debugLogging: true,
+ rotateDisplay: 0,
},
deviceModel: 'Raspberry Pi 4',
isLoading: false,
@@ -180,6 +181,7 @@ describe('Settings Component', () => {
shufflePlaylist: true,
use24HourClock: false,
debugLogging: true,
+ rotateDisplay: 0,
},
deviceModel: 'Raspberry Pi 4',
isLoading: true,
diff --git a/static/src/tests/utils.ts b/static/src/tests/utils.ts
index 621785daf..d1ac77ec7 100644
--- a/static/src/tests/utils.ts
+++ b/static/src/tests/utils.ts
@@ -154,6 +154,7 @@ export function getInitialState(): RootState {
shufflePlaylist: false,
use24HourClock: false,
debugLogging: false,
+ rotateDisplay: 0,
},
deviceModel: '',
prevAuthBackend: '',
diff --git a/static/src/types.ts b/static/src/types.ts
index c4e74c016..0566728c5 100644
--- a/static/src/types.ts
+++ b/static/src/types.ts
@@ -117,6 +117,7 @@ export interface RootState {
shufflePlaylist: boolean
use24HourClock: boolean
debugLogging: boolean
+ rotateDisplay: number
}
deviceModel: string
prevAuthBackend: string
@@ -174,6 +175,7 @@ export interface SettingsData {
shufflePlaylist: boolean
use24HourClock: boolean
debugLogging: boolean
+ rotateDisplay: number
}
export interface SystemOperationParams {
diff --git a/viewer/media_player.py b/viewer/media_player.py
index fba2db9e0..197f9353a 100644
--- a/viewer/media_player.py
+++ b/viewer/media_player.py
@@ -36,9 +36,34 @@ def __init__(self):
def set_asset(self, uri, duration):
self.uri = uri
+ def __get_rotation_filter(self):
+ rotation = settings.get('rotate_display', 0)
+ rotation_angles = {
+ 0: '',
+ 90: 'transpose=1',
+ 180: 'hflip,vflip',
+ 270: 'transpose=2',
+ }
+ return rotation_angles.get(rotation, '')
+
def play(self):
+ rotation_filter = self.__get_rotation_filter()
+ filters = []
+ if rotation_filter:
+ filters.append(rotation_filter)
+
+ vf_arg = ','.join(filters) if filters else None
+
+ cmd = [
+ 'ffplay',
+ '-autoexit',
+ ]
+ if vf_arg:
+ cmd.extend(['-vf', vf_arg])
+ cmd.append(self.uri)
+
self.process = subprocess.Popen(
- ['ffplay', '-autoexit', self.uri],
+ cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
@@ -82,8 +107,18 @@ def get_alsa_audio_device(self):
return 'default:CARD=HID'
def __get_options(self):
+ rotation = settings.get('rotate_display', 0)
+ rotation_angles = {
+ 0: 0,
+ 1: 90,
+ 2: 180,
+ 3: 270,
+ }
+ angle = rotation_angles.get(rotation, 0)
+
return [
f'--alsa-audio-device={self.get_alsa_audio_device()}',
+ f'--video-filter=rotate{{angle={angle}}}',
]
def set_asset(self, uri, duration):