mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-06 17:07:08 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 880725a105 | |||
| 6a6c13018e | |||
| 9ea4e31863 | |||
| cfb26a0b47 | |||
| df1ea7b163 | |||
| 013a3ca487 | |||
| 4cf0f12a6f | |||
| 9cafb293d0 | |||
| 78fde49329 | |||
| a7184847bb | |||
| fe847339e4 | |||
| 84c01d791a | |||
| 54902357b0 | |||
| 88b80fab58 |
@@ -10,6 +10,7 @@ Open source solution for advanced remote control and coordination of one or more
|
|||||||
- Bash
|
- Bash
|
||||||
- Chromium
|
- Chromium
|
||||||
- LibreOffice (optional, presentation view)
|
- LibreOffice (optional, presentation view)
|
||||||
|
- Xreader (optional, pdf view)
|
||||||
- ImageMagick (optional, image preview)
|
- ImageMagick (optional, image preview)
|
||||||
- ffmpeg (optional, video preview)
|
- ffmpeg (optional, video preview)
|
||||||
- Ghostscript (optional, pdf preview)
|
- Ghostscript (optional, pdf preview)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
import Button from './Button.svelte';
|
import Button from './Button.svelte';
|
||||||
import OnlineState from './OnlineState.svelte';
|
import OnlineState from './OnlineState.svelte';
|
||||||
import { cubicOut } from 'svelte/easing';
|
import { cubicOut } from 'svelte/easing';
|
||||||
import { Menu, Minus, Pencil, PinOff, Plus, Settings, Trash2, VideoOff } from 'lucide-svelte';
|
import { Menu, Pencil, PinOff, Settings, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte';
|
||||||
import { selected_display_ids } from '../ts/stores/select';
|
import { selected_display_ids } from '../ts/stores/select';
|
||||||
import { dragHandleZone } from 'svelte-dnd-action';
|
import { dragHandleZone } from 'svelte-dnd-action';
|
||||||
import { flip } from 'svelte/animate';
|
import { flip } from 'svelte/animate';
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
change_height('display', 1);
|
change_height('display', 1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Plus />
|
<ZoomIn />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
title="Bildschirme kleiner darstellen"
|
title="Bildschirme kleiner darstellen"
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
change_height('display', -1);
|
change_height('display', -1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Minus />
|
<ZoomOut />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
Download,
|
Download,
|
||||||
FolderPlus,
|
FolderPlus,
|
||||||
Info,
|
Info,
|
||||||
Minus,
|
|
||||||
Pen,
|
Pen,
|
||||||
Plus,
|
|
||||||
RefreshCcw,
|
RefreshCcw,
|
||||||
Scissors,
|
Scissors,
|
||||||
Trash2,
|
Trash2,
|
||||||
Upload
|
Upload,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
} from 'lucide-svelte';
|
} from 'lucide-svelte';
|
||||||
import { change_height, current_height, next_height_step_size } from '../ts/stores/ui_behavior';
|
import { change_height, current_height, next_height_step_size } from '../ts/stores/ui_behavior';
|
||||||
import Button from './Button.svelte';
|
import Button from './Button.svelte';
|
||||||
@@ -258,7 +258,7 @@
|
|||||||
change_height('file', 1);
|
change_height('file', 1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Plus />
|
<ZoomIn />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
title="Dateien kleiner darstellen"
|
title="Dateien kleiner darstellen"
|
||||||
@@ -269,7 +269,7 @@
|
|||||||
change_height('file', -1);
|
change_height('file', -1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Minus />
|
<ZoomOut />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/labstack/echo/v4 v4.13.4
|
github.com/labstack/echo/v4 v4.13.4
|
||||||
github.com/micmonay/keybd_event v1.1.2
|
github.com/micmonay/keybd_event v1.1.2
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.11
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
|||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
|
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"plg-mudics/shared"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FileHandler fileHandler = fileHandler{}
|
||||||
|
|
||||||
|
type fileHandler struct {
|
||||||
|
runningProgram *exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *fileHandler) OpenFile(path string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
mType, err := mimetype.DetectFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to detect mime type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tempDirPath, err := os.MkdirTemp("", "plg-mudics-program-profile-")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create temporary profile directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fh.CloseRunningProgram()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch mType.String() {
|
||||||
|
case "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.presentation":
|
||||||
|
fh.runningProgram = exec.Command("soffice", "--show", path, "--nologo", "--view", "--norestore", fmt.Sprintf("-env:UserInstallation=file://%s", tempDirPath))
|
||||||
|
case "application/pdf":
|
||||||
|
fh.runningProgram = exec.Command("xreader", path, "--presentation")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported file type: %s", mType.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
fh.runningProgram.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
|
||||||
|
result := shared.RunShellCommandNonBlocking(fh.runningProgram)
|
||||||
|
if result.ExitCode != 0 {
|
||||||
|
return fmt.Errorf("could not open pdf: %s (%d)", result.Stderr, result.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fh *fileHandler) CloseRunningProgram() error {
|
||||||
|
if fh.runningProgram == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := syscall.Kill(-fh.runningProgram.Process.Pid, syscall.SIGTERM)
|
||||||
|
fh.runningProgram = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -47,15 +47,6 @@ func GetDeviceMac() (string, error) {
|
|||||||
return "", fmt.Errorf("no suitable MAC address found")
|
return "", fmt.Errorf("no suitable MAC address found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenPresentation(path string) error {
|
|
||||||
cmd := exec.Command("bash", "-c", "-r", fmt.Sprintf("soffice --show %s -nologo -norestore", path))
|
|
||||||
result := shared.RunShellCommand(cmd)
|
|
||||||
if result.ExitCode != 0 {
|
|
||||||
return errors.New(result.Stderr)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeyAction int
|
type KeyAction int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
+57
-34
@@ -14,12 +14,10 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
shared "plg-mudics/shared"
|
shared "plg-mudics/shared"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/echo/v4/middleware"
|
"github.com/labstack/echo/v4/middleware"
|
||||||
"github.com/micmonay/keybd_event"
|
|
||||||
"github.com/skip2/go-qrcode"
|
"github.com/skip2/go-qrcode"
|
||||||
|
|
||||||
"plg-mudics/display/pkg"
|
"plg-mudics/display/pkg"
|
||||||
@@ -224,10 +222,13 @@ func keyboardInputRoute(ctx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func uploadFileRoute(ctx echo.Context) error {
|
func uploadFileRoute(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
fullPath := ctx.Get("fullPath").(string)
|
fullPath := ctx.Get("fullPath").(string)
|
||||||
|
|
||||||
// Ensure parent directories exist
|
// Ensure parent directories exist
|
||||||
if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
|
if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
|
||||||
|
slog.Error("Failed to create storage path", "error", err, "path", fullPath)
|
||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to prepare storage directory"})
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to prepare storage directory"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,12 +236,30 @@ func uploadFileRoute(ctx echo.Context) error {
|
|||||||
return ctx.JSON(http.StatusConflict, shared.ErrorResponse{Description: "File already exists"})
|
return ctx.JSON(http.StatusConflict, shared.ErrorResponse{Description: "File already exists"})
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := io.ReadAll(ctx.Request().Body)
|
file, err := os.Create(fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: shared.BadRequestDescription})
|
slog.Error("Failed to create file", "file", fullPath, "error", err)
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to create file"})
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
fileCloseErr := file.Close()
|
||||||
|
if fileCloseErr != nil {
|
||||||
|
slog.Error("Failed to close file", "file", fullPath, "error", fileCloseErr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(fullPath)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, err = io.Copy(file, ctx.Request().Body)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to write file", "file", fullPath, "error", err)
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to write file"})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(fullPath, data, os.ModePerm); err != nil {
|
err = file.Sync() // ensure data is flushed to disk
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to sync file to disk", "file", fullPath, "error", err)
|
||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to save file"})
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to save file"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,17 +274,21 @@ func downloadFileRoute(ctx echo.Context) error {
|
|||||||
return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"})
|
return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"})
|
||||||
}
|
}
|
||||||
|
|
||||||
err := ctx.File(fullPath)
|
slog.Info("Serving file for download", "path", fullPath)
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to serve file", "file", fullPath, "error", err)
|
|
||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to serve file"})
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Info("File downloaded successfully", "path", fullPath)
|
file, err := os.Open(fullPath)
|
||||||
return nil
|
if err != nil {
|
||||||
|
slog.Error("Failed to open file", "file", fullPath, "error", err)
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to open file"})
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
return ctx.Stream(http.StatusOK, "application/octet-stream", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openFileRoute(ctx echo.Context) error {
|
func openFileRoute(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
pathParam := ctx.Param("path")
|
pathParam := ctx.Param("path")
|
||||||
fullPath := ctx.Get("fullPath").(string)
|
fullPath := ctx.Get("fullPath").(string)
|
||||||
|
|
||||||
@@ -277,31 +300,38 @@ func openFileRoute(ctx echo.Context) error {
|
|||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Cant connect to display browser client"})
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Cant connect to display browser client"})
|
||||||
}
|
}
|
||||||
|
|
||||||
err := resetView()
|
err = resetView()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to reset view", "error", err)
|
slog.Error("Failed to reset view", "error", err)
|
||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to reset view"})
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to reset view"})
|
||||||
}
|
}
|
||||||
|
|
||||||
ext := strings.ToLower(filepath.Ext(fullPath))
|
mType, err := mimetype.DetectFile(fullPath)
|
||||||
switch ext {
|
if err != nil {
|
||||||
case ".mp4":
|
slog.Error("Failed to detect mime type", "file", pathParam, "error", err)
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to detect file type"})
|
||||||
|
}
|
||||||
|
|
||||||
|
switch mType.String() {
|
||||||
|
case "video/mp4":
|
||||||
var templateBuffer bytes.Buffer
|
var templateBuffer bytes.Buffer
|
||||||
videoTemplate(pathParam).Render(context.Background(), &templateBuffer)
|
videoTemplate(pathParam).Render(context.Background(), &templateBuffer)
|
||||||
|
|
||||||
sseConnection <- templateBuffer.String()
|
sseConnection <- templateBuffer.String()
|
||||||
case ".jpg", ".jpeg", ".png", ".gif":
|
case "image/jpeg", "image/png", "image/gif":
|
||||||
var templateBuffer bytes.Buffer
|
var templateBuffer bytes.Buffer
|
||||||
imageTemplate(pathParam).Render(context.Background(), &templateBuffer)
|
imageTemplate(pathParam).Render(context.Background(), &templateBuffer)
|
||||||
sseConnection <- templateBuffer.String()
|
sseConnection <- templateBuffer.String()
|
||||||
case ".pptx", ".odp":
|
case "application/pdf", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.presentation":
|
||||||
err := pkg.OpenPresentation(fullPath)
|
err = pkg.FileHandler.OpenFile(fullPath)
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to open presentation", "file", pathParam, "error", err)
|
|
||||||
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to open presentation"})
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return ctx.JSON(http.StatusUnsupportedMediaType, shared.ErrorResponse{Description: "Unsupported file type"})
|
slog.Info("Unsupported file type", "type", mType)
|
||||||
|
return ctx.JSON(http.StatusUnsupportedMediaType, shared.ErrorResponse{Description: "Unsupported file type: " + mType.String()})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to open file", "file", pathParam, "error", err)
|
||||||
|
return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to open file"})
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("Successfully run file", "file", pathParam)
|
slog.Info("Successfully run file", "file", pathParam)
|
||||||
@@ -377,16 +407,9 @@ func previewRoute(ctx echo.Context) error {
|
|||||||
|
|
||||||
// Reset previous file views so they dont collide with the new one
|
// Reset previous file views so they dont collide with the new one
|
||||||
func resetView() error {
|
func resetView() error {
|
||||||
var err error
|
err := pkg.FileHandler.CloseRunningProgram()
|
||||||
|
|
||||||
err = pkg.KeyboardInput(keybd_event.VK_ESC, pkg.KeyPress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to send ESC key: %w", err)
|
return fmt.Errorf("failed to close running program: %w", err)
|
||||||
}
|
|
||||||
time.Sleep(400 * time.Millisecond)
|
|
||||||
err = pkg.KeyboardInput(keybd_event.VK_ESC, pkg.KeyRelease)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to send ESC key: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sseConnection <- ""
|
sseConnection <- ""
|
||||||
|
|||||||
Generated
+27
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765779637,
|
||||||
|
"narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "1306659b587dc277866c7b69eb97e5f07864d8c4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
}: let
|
||||||
|
pkgs = nixpkgs.legacyPackages."x86_64-linux";
|
||||||
|
in {
|
||||||
|
devShells."x86_64-linux".default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
libreoffice
|
||||||
|
ungoogled-chromium
|
||||||
|
xreader
|
||||||
|
imagemagick
|
||||||
|
ffmpeg
|
||||||
|
ghostscript
|
||||||
|
gnome-screenshot
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
+18
-2
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
inputs,
|
||||||
config,
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
imports = [
|
imports = [
|
||||||
|
inputs.home-manager.nixosModules.default
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@
|
|||||||
boot.loader.systemd-boot.enable = true;
|
boot.loader.systemd-boot.enable = true;
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
hardware.steam-hardware.enable = true;
|
||||||
|
|
||||||
networking.networkmanager.enable = true;
|
networking.networkmanager.enable = true;
|
||||||
|
|
||||||
nix.settings.experimental-features = ["nix-command" "flakes"];
|
nix.settings.experimental-features = ["nix-command" "flakes"];
|
||||||
@@ -87,6 +91,9 @@
|
|||||||
xfce.thunar-archive-plugin
|
xfce.thunar-archive-plugin
|
||||||
git
|
git
|
||||||
nushell
|
nushell
|
||||||
|
unzip
|
||||||
|
iputils
|
||||||
|
xreader
|
||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
imagemagick
|
imagemagick
|
||||||
@@ -94,11 +101,20 @@
|
|||||||
ghostscript
|
ghostscript
|
||||||
];
|
];
|
||||||
|
|
||||||
|
home-manager.users.mudics = {
|
||||||
|
xfconf.settings = {
|
||||||
|
xfce4-power-manager."xfce4-power-manager/dpms-enabled" = false;
|
||||||
|
xfce4-screensaver."saver/enabled" = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.stateVersion = "25.05";
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.update-mudics = {
|
systemd.services.update-mudics = {
|
||||||
wantedBy = ["multi-user.target"];
|
wantedBy = ["multi-user.target"];
|
||||||
after = ["network-online.target"];
|
after = ["network-online.target"];
|
||||||
wants = ["network-online.target"];
|
wants = ["network-online.target"];
|
||||||
path = with pkgs; [nushell unzip iputils];
|
path = config.environment.systemPackages;
|
||||||
script = "nu ${./update.sh}";
|
script = "nu ${./update.sh}";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
WorkingDirectory = "/home/mudics/mudics";
|
WorkingDirectory = "/home/mudics/mudics";
|
||||||
@@ -111,7 +127,7 @@
|
|||||||
wantedBy = ["default.target"];
|
wantedBy = ["default.target"];
|
||||||
after = ["update-mudics.service" "graphical.target"];
|
after = ["update-mudics.service" "graphical.target"];
|
||||||
wants = ["graphical.target"];
|
wants = ["graphical.target"];
|
||||||
path = with pkgs; [ungoogled-chromium];
|
path = config.environment.systemPackages;
|
||||||
script = "./plg-mudics-display";
|
script = "./plg-mudics-display";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
WorkingDirectory = "/home/mudics/mudics";
|
WorkingDirectory = "/home/mudics/mudics";
|
||||||
|
|||||||
Generated
+22
@@ -1,5 +1,26 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1763992789,
|
||||||
|
"narHash": "sha256-WHkdBlw6oyxXIra/vQPYLtqY+3G8dUVZM8bEXk0t8x4=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "44831a7eaba4360fb81f2acc5ea6de5fde90aaa3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"ref": "release-25.05",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761999846,
|
"lastModified": 1761999846,
|
||||||
@@ -18,6 +39,7 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"home-manager": "home-manager",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-8
@@ -1,6 +1,11 @@
|
|||||||
{
|
{
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
|
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager/release-25.05";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
@@ -8,14 +13,15 @@
|
|||||||
nixpkgs,
|
nixpkgs,
|
||||||
...
|
...
|
||||||
} @ inputs: {
|
} @ inputs: {
|
||||||
nixosConfigurations.plg-mudics = nixpkgs.lib.nixosSystem {
|
nixosConfigurations.mudics = nixpkgs.lib.nixosSystem {
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit inputs;
|
inherit inputs;
|
||||||
};
|
|
||||||
modules = [
|
|
||||||
./configuration.nix
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
modules = [
|
||||||
|
./configuration.nix
|
||||||
|
inputs.home-manager.nixosModules.default
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package shared
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommandResponse struct {
|
type CommandResponse struct {
|
||||||
@@ -24,6 +26,34 @@ func RunShellCommand(cmd *exec.Cmd) CommandResponse {
|
|||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
|
||||||
|
return parseCmdResult(cmd, stdout, stderr, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunShellCommandNonBlocking(cmd *exec.Cmd) CommandResponse {
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
cmd.Start()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
done := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
done <- cmd.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return CommandResponse{}
|
||||||
|
case err := <-done:
|
||||||
|
return parseCmdResult(cmd, stdout, stderr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCmdResult(cmd *exec.Cmd, stdout, stderr bytes.Buffer, err error) CommandResponse {
|
||||||
commandOutput := CommandResponse{
|
commandOutput := CommandResponse{
|
||||||
Stdout: stdout.String(),
|
Stdout: stdout.String(),
|
||||||
Stderr: stderr.String(),
|
Stderr: stderr.String(),
|
||||||
|
|||||||
Reference in New Issue
Block a user