summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2026-01-08 16:26:49 -0500
committerFreya Murphy <freya@freyacat.org>2026-01-08 16:26:49 -0500
commit5581a4b34f7ef70005a26e2b955df33414533791 (patch)
treefc8a46997292aa9632216c1c904deb3858fd19c0
parentonly support one color scheme (diff)
downloadcaelestia-shell-5581a4b34f7ef70005a26e2b955df33414533791.tar.gz
caelestia-shell-5581a4b34f7ef70005a26e2b955df33414533791.tar.bz2
caelestia-shell-5581a4b34f7ef70005a26e2b955df33414533791.zip
remove recording
-rw-r--r--modules/utilities/Content.qml10
-rw-r--r--modules/utilities/RecordingDeleteModal.qml208
-rw-r--r--modules/utilities/Wrapper.qml4
-rw-r--r--modules/utilities/cards/Record.qml277
-rw-r--r--modules/utilities/cards/RecordingList.qml242
-rw-r--r--services/Recorder.qml82
-rw-r--r--utils/Icons.qml3
-rw-r--r--utils/Paths.qml1
8 files changed, 0 insertions, 827 deletions
diff --git a/modules/utilities/Content.qml b/modules/utilities/Content.qml
index 902656d..f6d8d63 100644
--- a/modules/utilities/Content.qml
+++ b/modules/utilities/Content.qml
@@ -21,19 +21,9 @@ Item {
IdleInhibit {}
- Record {
- props: root.props
- visibilities: root.visibilities
- z: 1
- }
-
Toggles {
visibilities: root.visibilities
popouts: root.popouts
}
}
-
- RecordingDeleteModal {
- props: root.props
- }
}
diff --git a/modules/utilities/RecordingDeleteModal.qml b/modules/utilities/RecordingDeleteModal.qml
deleted file mode 100644
index e832c27..0000000
--- a/modules/utilities/RecordingDeleteModal.qml
+++ /dev/null
@@ -1,208 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import qs.components
-import qs.components.controls
-import qs.components.effects
-import qs.services
-import qs.config
-import Caelestia
-import QtQuick
-import QtQuick.Layouts
-import QtQuick.Shapes
-
-Loader {
- id: root
-
- required property var props
-
- anchors.fill: parent
-
- opacity: root.props.recordingConfirmDelete ? 1 : 0
- active: opacity > 0
- asynchronous: true
-
- sourceComponent: MouseArea {
- id: deleteConfirmation
-
- property string path
-
- Component.onCompleted: path = root.props.recordingConfirmDelete
-
- hoverEnabled: true
- onClicked: root.props.recordingConfirmDelete = ""
-
- Item {
- anchors.fill: parent
- anchors.margins: -Appearance.padding.large
- anchors.rightMargin: -Appearance.padding.large - Config.border.thickness
- anchors.bottomMargin: -Appearance.padding.large - Config.border.thickness
- opacity: 0.5
-
- StyledRect {
- anchors.fill: parent
- topLeftRadius: Config.border.rounding
- color: Colours.palette.m3scrim
- }
-
- Shape {
- id: shape
-
- anchors.fill: parent
- preferredRendererType: Shape.CurveRenderer
- asynchronous: true
-
- ShapePath {
- startX: -Config.border.rounding * 2
- startY: shape.height - Config.border.thickness
- strokeWidth: 0
- fillGradient: LinearGradient {
- orientation: LinearGradient.Horizontal
- x1: -Config.border.rounding * 2
-
- GradientStop {
- position: 0
- color: Qt.alpha(Colours.palette.m3scrim, 0)
- }
- GradientStop {
- position: 1
- color: Colours.palette.m3scrim
- }
- }
-
- PathLine {
- relativeX: Config.border.rounding
- relativeY: 0
- }
- PathArc {
- relativeY: -Config.border.rounding
- radiusX: Config.border.rounding
- radiusY: Config.border.rounding
- direction: PathArc.Counterclockwise
- }
- PathLine {
- relativeX: 0
- relativeY: Config.border.rounding + Config.border.thickness
- }
- PathLine {
- relativeX: -Config.border.rounding * 2
- relativeY: 0
- }
- }
-
- ShapePath {
- startX: shape.width - Config.border.rounding - Config.border.thickness
- strokeWidth: 0
- fillGradient: LinearGradient {
- orientation: LinearGradient.Vertical
- y1: -Config.border.rounding * 2
-
- GradientStop {
- position: 0
- color: Qt.alpha(Colours.palette.m3scrim, 0)
- }
- GradientStop {
- position: 1
- color: Colours.palette.m3scrim
- }
- }
-
- PathArc {
- relativeX: Config.border.rounding
- relativeY: -Config.border.rounding
- radiusX: Config.border.rounding
- radiusY: Config.border.rounding
- direction: PathArc.Counterclockwise
- }
- PathLine {
- relativeX: 0
- relativeY: -Config.border.rounding
- }
- PathLine {
- relativeX: Config.border.thickness
- relativeY: 0
- }
- PathLine {
- relativeX: 0
- }
- }
- }
- }
-
- StyledRect {
- anchors.centerIn: parent
- radius: Appearance.rounding.large
- color: Colours.palette.m3surfaceContainerHigh
-
- scale: 0
- Component.onCompleted: scale = Qt.binding(() => root.props.recordingConfirmDelete ? 1 : 0)
-
- width: Math.min(parent.width - Appearance.padding.large * 2, implicitWidth)
- implicitWidth: deleteConfirmationLayout.implicitWidth + Appearance.padding.large * 3
- implicitHeight: deleteConfirmationLayout.implicitHeight + Appearance.padding.large * 3
-
- MouseArea {
- anchors.fill: parent
- }
-
- Elevation {
- anchors.fill: parent
- radius: parent.radius
- z: -1
- level: 3
- }
-
- ColumnLayout {
- id: deleteConfirmationLayout
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.large * 1.5
- spacing: Appearance.spacing.normal
-
- StyledText {
- text: qsTr("Delete recording?")
- font.pointSize: Appearance.font.size.large
- }
-
- StyledText {
- Layout.fillWidth: true
- text: qsTr("Recording '%1' will be permanently deleted.").arg(deleteConfirmation.path)
- color: Colours.palette.m3onSurfaceVariant
- font.pointSize: Appearance.font.size.small
- wrapMode: Text.WrapAtWordBoundaryOrAnywhere
- }
-
- RowLayout {
- Layout.topMargin: Appearance.spacing.normal
- Layout.alignment: Qt.AlignRight
- spacing: Appearance.spacing.normal
-
- TextButton {
- text: qsTr("Cancel")
- type: TextButton.Text
- onClicked: root.props.recordingConfirmDelete = ""
- }
-
- TextButton {
- text: qsTr("Delete")
- type: TextButton.Text
- onClicked: {
- CUtils.deleteFile(Qt.resolvedUrl(root.props.recordingConfirmDelete));
- root.props.recordingConfirmDelete = "";
- }
- }
- }
- }
-
- Behavior on scale {
- Anim {
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
- }
- }
-
- Behavior on opacity {
- Anim {}
- }
-}
diff --git a/modules/utilities/Wrapper.qml b/modules/utilities/Wrapper.qml
index 77178e3..455b5fa 100644
--- a/modules/utilities/Wrapper.qml
+++ b/modules/utilities/Wrapper.qml
@@ -13,10 +13,6 @@ Item {
required property Item popouts
readonly property PersistentProperties props: PersistentProperties {
- property bool recordingListExpanded: false
- property string recordingConfirmDelete
- property string recordingMode
-
reloadableId: "utilities"
}
readonly property bool shouldBeActive: visibilities.sidebar || (visibilities.utilities && Config.utilities.enabled && !(visibilities.session && Config.session.enabled))
diff --git a/modules/utilities/cards/Record.qml b/modules/utilities/cards/Record.qml
deleted file mode 100644
index 273c640..0000000
--- a/modules/utilities/cards/Record.qml
+++ /dev/null
@@ -1,277 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import qs.components
-import qs.components.controls
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Layouts
-
-StyledRect {
- id: root
-
- required property var props
- required property var visibilities
-
- Layout.fillWidth: true
- implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: layout
-
- anchors.fill: parent
- anchors.margins: Appearance.padding.large
- spacing: Appearance.spacing.normal
-
- RowLayout {
- spacing: Appearance.spacing.normal
- z: 1
-
- StyledRect {
- implicitWidth: implicitHeight
- implicitHeight: {
- const h = icon.implicitHeight + Appearance.padding.smaller * 2;
- return h - (h % 2);
- }
-
- radius: Appearance.rounding.full
- color: Recorder.running ? Colours.palette.m3secondary : Colours.palette.m3secondaryContainer
-
- MaterialIcon {
- id: icon
-
- anchors.centerIn: parent
- anchors.horizontalCenterOffset: -0.5
- anchors.verticalCenterOffset: 1.5
- text: "screen_record"
- color: Recorder.running ? Colours.palette.m3onSecondary : Colours.palette.m3onSecondaryContainer
- font.pointSize: Appearance.font.size.large
- }
- }
-
- ColumnLayout {
- Layout.fillWidth: true
- spacing: 0
-
- StyledText {
- Layout.fillWidth: true
- text: qsTr("Screen Recorder")
- font.pointSize: Appearance.font.size.normal
- elide: Text.ElideRight
- }
-
- StyledText {
- Layout.fillWidth: true
- text: Recorder.paused ? qsTr("Recording paused") : Recorder.running ? qsTr("Recording running") : qsTr("Recording off")
- color: Colours.palette.m3onSurfaceVariant
- font.pointSize: Appearance.font.size.small
- elide: Text.ElideRight
- }
- }
-
- SplitButton {
- disabled: Recorder.running
- active: menuItems.find(m => root.props.recordingMode === m.icon + m.text) ?? menuItems[0]
- menu.onItemSelected: item => root.props.recordingMode = item.icon + item.text
-
- menuItems: [
- MenuItem {
- icon: "fullscreen"
- text: qsTr("Record fullscreen")
- activeText: qsTr("Fullscreen")
- onClicked: Recorder.start()
- },
- MenuItem {
- icon: "screenshot_region"
- text: qsTr("Record region")
- activeText: qsTr("Region")
- onClicked: Recorder.start(["-r"])
- },
- MenuItem {
- icon: "select_to_speak"
- text: qsTr("Record fullscreen with sound")
- activeText: qsTr("Fullscreen")
- onClicked: Recorder.start(["-s"])
- },
- MenuItem {
- icon: "volume_up"
- text: qsTr("Record region with sound")
- activeText: qsTr("Region")
- onClicked: Recorder.start(["-sr"])
- }
- ]
- }
- }
-
- Loader {
- id: listOrControls
-
- property bool running: Recorder.running
-
- Layout.fillWidth: true
- Layout.preferredHeight: implicitHeight
- sourceComponent: running ? recordingControls : recordingList
-
- Behavior on Layout.preferredHeight {
- id: locHeightAnim
-
- enabled: false
-
- Anim {}
- }
-
- Behavior on running {
- SequentialAnimation {
- ParallelAnimation {
- Anim {
- target: listOrControls
- property: "scale"
- to: 0.7
- duration: Appearance.anim.durations.small
- easing.bezierCurve: Appearance.anim.curves.standardAccel
- }
- Anim {
- target: listOrControls
- property: "opacity"
- to: 0
- duration: Appearance.anim.durations.small
- easing.bezierCurve: Appearance.anim.curves.standardAccel
- }
- }
- PropertyAction {
- target: locHeightAnim
- property: "enabled"
- value: true
- }
- PropertyAction {}
- PropertyAction {
- target: locHeightAnim
- property: "enabled"
- value: false
- }
- ParallelAnimation {
- Anim {
- target: listOrControls
- property: "scale"
- to: 1
- duration: Appearance.anim.durations.small
- easing.bezierCurve: Appearance.anim.curves.standardDecel
- }
- Anim {
- target: listOrControls
- property: "opacity"
- to: 1
- duration: Appearance.anim.durations.small
- easing.bezierCurve: Appearance.anim.curves.standardDecel
- }
- }
- }
- }
- }
- }
-
- Component {
- id: recordingList
-
- RecordingList {
- props: root.props
- visibilities: root.visibilities
- }
- }
-
- Component {
- id: recordingControls
-
- RowLayout {
- spacing: Appearance.spacing.normal
-
- StyledRect {
- radius: Appearance.rounding.full
- color: Recorder.paused ? Colours.palette.m3tertiary : Colours.palette.m3error
-
- implicitWidth: recText.implicitWidth + Appearance.padding.normal * 2
- implicitHeight: recText.implicitHeight + Appearance.padding.smaller * 2
-
- StyledText {
- id: recText
-
- anchors.centerIn: parent
- animate: true
- text: Recorder.paused ? "PAUSED" : "REC"
- color: Recorder.paused ? Colours.palette.m3onTertiary : Colours.palette.m3onError
- font.family: Appearance.font.family.mono
- }
-
- Behavior on implicitWidth {
- Anim {}
- }
-
- SequentialAnimation on opacity {
- running: !Recorder.paused
- alwaysRunToEnd: true
- loops: Animation.Infinite
-
- Anim {
- from: 1
- to: 0
- duration: Appearance.anim.durations.large
- easing.bezierCurve: Appearance.anim.curves.emphasizedAccel
- }
- Anim {
- from: 0
- to: 1
- duration: Appearance.anim.durations.extraLarge
- easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
- }
- }
- }
-
- StyledText {
- text: {
- const elapsed = Recorder.elapsed;
-
- const hours = Math.floor(elapsed / 3600);
- const mins = Math.floor((elapsed % 3600) / 60);
- const secs = Math.floor(elapsed % 60).toString().padStart(2, "0");
-
- let time;
- if (hours > 0)
- time = `${hours}:${mins.toString().padStart(2, "0")}:${secs}`;
- else
- time = `${mins}:${secs}`;
-
- return qsTr("Recording for %1").arg(time);
- }
- font.pointSize: Appearance.font.size.normal
- }
-
- Item {
- Layout.fillWidth: true
- }
-
- IconButton {
- label.animate: true
- icon: Recorder.paused ? "play_arrow" : "pause"
- toggle: true
- checked: Recorder.paused
- type: IconButton.Tonal
- font.pointSize: Appearance.font.size.large
- onClicked: {
- Recorder.togglePause();
- internalChecked = Recorder.paused;
- }
- }
-
- IconButton {
- icon: "stop"
- inactiveColour: Colours.palette.m3error
- inactiveOnColour: Colours.palette.m3onError
- font.pointSize: Appearance.font.size.large
- onClicked: Recorder.stop()
- }
- }
- }
-}
diff --git a/modules/utilities/cards/RecordingList.qml b/modules/utilities/cards/RecordingList.qml
deleted file mode 100644
index 5d71328..0000000
--- a/modules/utilities/cards/RecordingList.qml
+++ /dev/null
@@ -1,242 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import qs.components
-import qs.components.controls
-import qs.components.containers
-import qs.services
-import qs.config
-import qs.utils
-import Caelestia
-import Caelestia.Models
-import Quickshell
-import Quickshell.Widgets
-import QtQuick
-import QtQuick.Layouts
-
-ColumnLayout {
- id: root
-
- required property var props
- required property var visibilities
-
- spacing: 0
-
- WrapperMouseArea {
- Layout.fillWidth: true
-
- cursorShape: Qt.PointingHandCursor
- onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
-
- RowLayout {
- spacing: Appearance.spacing.smaller
-
- MaterialIcon {
- Layout.alignment: Qt.AlignVCenter
- text: "list"
- font.pointSize: Appearance.font.size.large
- }
-
- StyledText {
- Layout.alignment: Qt.AlignVCenter
- Layout.fillWidth: true
- text: qsTr("Recordings")
- font.pointSize: Appearance.font.size.normal
- }
-
- IconButton {
- icon: root.props.recordingListExpanded ? "unfold_less" : "unfold_more"
- type: IconButton.Text
- label.animate: true
- onClicked: root.props.recordingListExpanded = !root.props.recordingListExpanded
- }
- }
- }
-
- StyledListView {
- id: list
-
- model: FileSystemModel {
- path: Paths.recsdir
- nameFilters: ["recording_*.mp4"]
- sortReverse: true
- }
-
- Layout.fillWidth: true
- Layout.rightMargin: -Appearance.spacing.small
- implicitHeight: (Appearance.font.size.larger + Appearance.padding.small) * (root.props.recordingListExpanded ? 10 : 3)
- clip: true
-
- StyledScrollBar.vertical: StyledScrollBar {
- flickable: list
- }
-
- delegate: RowLayout {
- id: recording
-
- required property FileSystemEntry modelData
- property string baseName
-
- anchors.left: list.contentItem.left
- anchors.right: list.contentItem.right
- anchors.rightMargin: Appearance.spacing.small
- spacing: Appearance.spacing.small / 2
-
- Component.onCompleted: baseName = modelData.baseName
-
- StyledText {
- Layout.fillWidth: true
- Layout.rightMargin: Appearance.spacing.small / 2
- text: {
- const time = recording.baseName;
- const matches = time.match(/^recording_(\d{4})(\d{2})(\d{2})_(\d{2})-(\d{2})-(\d{2})/);
- if (!matches)
- return time;
- const date = new Date(...matches.slice(1));
- date.setMonth(date.getMonth() - 1); // Woe (months start from 0)
- return qsTr("Recording at %1").arg(Qt.formatDateTime(date, Qt.locale()));
- }
- color: Colours.palette.m3onSurfaceVariant
- elide: Text.ElideRight
- }
-
- IconButton {
- icon: "play_arrow"
- type: IconButton.Text
- onClicked: {
- root.visibilities.utilities = false;
- root.visibilities.sidebar = false;
- Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.playback, recording.modelData.path]);
- }
- }
-
- IconButton {
- icon: "folder"
- type: IconButton.Text
- onClicked: {
- root.visibilities.utilities = false;
- root.visibilities.sidebar = false;
- Quickshell.execDetached(["app2unit", "--", ...Config.general.apps.explorer, recording.modelData.path]);
- }
- }
-
- IconButton {
- icon: "delete_forever"
- type: IconButton.Text
- label.color: Colours.palette.m3error
- stateLayer.color: Colours.palette.m3error
- onClicked: root.props.recordingConfirmDelete = recording.modelData.path
- }
- }
-
- add: Transition {
- Anim {
- property: "opacity"
- from: 0
- to: 1
- }
- Anim {
- property: "scale"
- from: 0.5
- to: 1
- }
- }
-
- remove: Transition {
- Anim {
- property: "opacity"
- to: 0
- }
- Anim {
- property: "scale"
- to: 0.5
- }
- }
-
- displaced: Transition {
- Anim {
- properties: "opacity,scale"
- to: 1
- }
- Anim {
- property: "y"
- }
- }
-
- Loader {
- anchors.centerIn: parent
-
- opacity: list.count === 0 ? 1 : 0
- active: opacity > 0
- asynchronous: true
-
- sourceComponent: ColumnLayout {
- spacing: Appearance.spacing.small
-
- MaterialIcon {
- Layout.alignment: Qt.AlignHCenter
- text: "scan_delete"
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.extraLarge
-
- opacity: root.props.recordingListExpanded ? 1 : 0
- scale: root.props.recordingListExpanded ? 1 : 0
- Layout.preferredHeight: root.props.recordingListExpanded ? implicitHeight : 0
-
- Behavior on opacity {
- Anim {}
- }
-
- Behavior on scale {
- Anim {}
- }
-
- Behavior on Layout.preferredHeight {
- Anim {}
- }
- }
-
- RowLayout {
- spacing: Appearance.spacing.smaller
-
- MaterialIcon {
- Layout.alignment: Qt.AlignHCenter
- text: "scan_delete"
- color: Colours.palette.m3outline
-
- opacity: !root.props.recordingListExpanded ? 1 : 0
- scale: !root.props.recordingListExpanded ? 1 : 0
- Layout.preferredWidth: !root.props.recordingListExpanded ? implicitWidth : 0
-
- Behavior on opacity {
- Anim {}
- }
-
- Behavior on scale {
- Anim {}
- }
-
- Behavior on Layout.preferredWidth {
- Anim {}
- }
- }
-
- StyledText {
- text: qsTr("No recordings found")
- color: Colours.palette.m3outline
- }
- }
- }
-
- Behavior on opacity {
- Anim {}
- }
- }
-
- Behavior on implicitHeight {
- Anim {
- duration: Appearance.anim.durations.expressiveDefaultSpatial
- easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
- }
- }
- }
-}
diff --git a/services/Recorder.qml b/services/Recorder.qml
deleted file mode 100644
index e4ce6a8..0000000
--- a/services/Recorder.qml
+++ /dev/null
@@ -1,82 +0,0 @@
-pragma Singleton
-
-import Quickshell
-import Quickshell.Io
-import QtQuick
-
-Singleton {
- id: root
-
- readonly property alias running: props.running
- readonly property alias paused: props.paused
- readonly property alias elapsed: props.elapsed
- property bool needsStart
- property list<string> startArgs
- property bool needsStop
- property bool needsPause
-
- function start(extraArgs: list<string>): void {
- needsStart = true;
- startArgs = extraArgs;
- checkProc.running = true;
- }
-
- function stop(): void {
- needsStop = true;
- checkProc.running = true;
- }
-
- function togglePause(): void {
- needsPause = true;
- checkProc.running = true;
- }
-
- PersistentProperties {
- id: props
-
- property bool running: false
- property bool paused: false
- property real elapsed: 0 // Might get too large for int
-
- reloadableId: "recorder"
- }
-
- Process {
- id: checkProc
-
- running: true
- command: ["pidof", "gpu-screen-recorder"]
- onExited: code => {
- props.running = code === 0;
-
- if (code === 0) {
- if (root.needsStop) {
- Quickshell.execDetached(["caelestia", "record"]);
- props.running = false;
- props.paused = false;
- } else if (root.needsPause) {
- Quickshell.execDetached(["caelestia", "record", "-p"]);
- props.paused = !props.paused;
- }
- } else if (root.needsStart) {
- Quickshell.execDetached(["caelestia", "record", ...root.startArgs]);
- props.running = true;
- props.paused = false;
- props.elapsed = 0;
- }
-
- root.needsStart = false;
- root.needsStop = false;
- root.needsPause = false;
- }
- }
-
- Connections {
- target: Time
- // enabled: props.running && !props.paused
-
- function onSecondsChanged(): void {
- props.elapsed++;
- }
- }
-}
diff --git a/utils/Icons.qml b/utils/Icons.qml
index c06cbf8..50b0592 100644
--- a/utils/Icons.qml
+++ b/utils/Icons.qml
@@ -52,7 +52,6 @@ Singleton {
Audio: "music_note",
Music: "music_note",
Player: "music_note",
- Recorder: "mic",
Game: "sports_esports",
FileTools: "files",
FileManager: "files",
@@ -144,8 +143,6 @@ Singleton {
summary = summary.toLowerCase();
if (summary.includes("reboot"))
return "restart_alt";
- if (summary.includes("recording"))
- return "screen_record";
if (summary.includes("battery"))
return "power";
if (summary.includes("screenshot"))
diff --git a/utils/Paths.qml b/utils/Paths.qml
index f95134f..5c8cb68 100644
--- a/utils/Paths.qml
+++ b/utils/Paths.qml
@@ -19,7 +19,6 @@ Singleton {
readonly property string imagecache: `${cache}/imagecache`
readonly property string notifimagecache: `${imagecache}/notifs`
readonly property string wallsdir: Quickshell.env("CAELESTIA_WALLPAPERS_DIR") || absolutePath(Config.paths.wallpaperDir)
- readonly property string recsdir: Quickshell.env("CAELESTIA_RECORDINGS_DIR") || `${videos}/Recordings`
readonly property string libdir: Quickshell.env("CAELESTIA_LIB_DIR") || "/usr/lib/caelestia"
function toLocalFile(path: url): string {