Full Code of phisch/giph for AI

master 6cee9780fa6a cached
5 files
21.7 KB
7.1k tokens
1 requests
Download .txt
Repository: phisch/giph
Branch: master
Commit: 6cee9780fa6a
Files: 5
Total size: 21.7 KB

Directory structure:
gitextract_icb2cw67/

├── LICENSE
├── Makefile
├── README.md
├── man/
│   └── giph.1
└── src/
    └── giph

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Philipp Schaffrath

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
PREFIX ?= /usr/local
DESTDIR ?=
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man

all:
	@echo "Nothing to do, try \"make install\" instead."

install-common:
	@install -v -d "$(DESTDIR)$(MANDIR)/man1" && install -m 0644 -v man/giph.1 "$(DESTDIR)$(MANDIR)/man1/giph.1"

install: install-common
	@install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v src/giph "$(DESTDIR)$(BINDIR)/giph"

uninstall:
	@rm -vrf \
		"$(DESTDIR)$(BINDIR)/giph" \
		"$(DESTDIR)$(MANDIR)/man1/giph.1"

.PHONY: install uninstall install-common


================================================
FILE: README.md
================================================
# giph
giph is a screen recorder that records the desktop, a window or selection and encodes it into a gif file. It prints the encoded gif directly to standard output when omitting the output filename.

![demo](https://i.imgur.com/Hoi0fF7.gif)

*I used **giph** to record a gif of **giph** recording a gif*.

## Examples

```bash
$ giph -s -l -c 1,1,1,0.3 -b 5 -p -5 out.gif 
```
Select a window or area with slop. The selection rectangle is highlighted in a transparent blue color abd has a 5px border on the inside. 
After stopping the recording with either `ctrl+c`, by running `giph --stop` or by sending a `SIGINT` to the processgroup, the resulting gif is written to `out.gif`.


```bash
$ giph -g 100x200+0+0 -d 5 -t 10
```
Records a 100x200 pixel rectangle in the top left corner of the screen. The recording starts after a 5 seconds countdown and will record for exactly 10 seconds. The resulting gif will be printed to standard output, which makes this able to be piped into other scripts like a file-upload to an image hosting service.


```bash
$ giph -f 30 -t 5 -s -a -m out.webm
```
Records a 5 second video of the users selection at 30 fps. The recording also contains the users desktop audio and microphone. If the recording fails because the default audio source `0` is not the correct one, run `pacmd list-sources` to get the correct source `index` or `name` and pass it to the `-as` parameter instead of using `-a`. Example: `giph -f 30 -t 5 -s -as 1 -m out.webm` (using id) or `giph -f 30 -t 5 -s -as alsa_output.pci-0000_04_00.1.hdmi-stereo.monitor -m out.webm` (using name)

```bash
$ giph -s -t 10 --format webm | curl -F "file=@-" 0x0.st | xclip -selection clipboard
```

Records a 10 second webm of the users selection, uploads the video to 0x0.st using curl and copies the returned url to the clipboard.

## Installation

### Arch

```bash
$ yay -S giph
```
Or install [giph-git](https://aur.archlinux.org/packages/giph-git/) to get the latest development version.

### From source

Make sure to install the following dependencies:

 - ffmpeg
 - xdotool

Optionally, install the following dependencies:

 - slop (`--select`)
 - libnotify (`--notify`)
 - pgrep (`--stop`)

Clone the giph repository:

```bash
$ git clone https://github.com/phisch/giph.git
```

And finally install giph:

```bash
$ cd giph
$ sudo make install
```

## Desktop Makers

<a href="https://discord.gg/RqKTeA4uxW" title="Desktop Makers Discord"><img align="left" width="72" alt="type=discord" src="https://user-images.githubusercontent.com/1282767/161089772-d7ad28bf-76eb-4951-b0f0-985afd5ea57a.png"></a>

I am actively working on giph and other cool projects on the [Desktop Makers Discord](https://discord.gg/RqKTeA4uxW). It aims to be a community for communities of Linux desktop related projects. If you are looking to collaborate with or want to contribute to great projects, this might be the right place for you.


================================================
FILE: man/giph.1
================================================
.TH GIPH 1 "April 2019" "MIT License" "User Commands"
.SH NAME
giph \- record gif from desktop, window or selection
.SH SYNOPSIS
.B giph
.RI [ OPTIONS "] [" FILENAME ]
.br
.B giph
[\fB-g\fR \fIGEOMETRY\fR |
\fB-w\fR \fIINT\fR |
\fB-s\fR [\fB-l\fR] [\fB-c\fR \fIFLOAT,FLOAT,FLOAT,FLOAT\fR] [\fB-p\fR \fIFLOAT\fR] [\fB-b\fR \fIFLOAT\fR]]
[\fB-d\fR \fIINT\fR]
[\fB-t\fR \fIINT\fR]
[\fB-f\fR \fIINT\fR]
[\fB--format\fR \fISTRING\fR]
[\fB-a\fR | \fB -as \fISTRING\fR]
[\fB-m\fR | \fB -ms \fISTRING\fR]
[\fIFILENAME\fR]
.SH DESCRIPTION
.B giph
is a screen recorder that records the desktop, a window or selection and encodes it into a video file.
.br
The recorded video file is encoded in one of the supported formats, gif, webm, mp4 or mkv based on the file extension given in [\fIFILENAME\fR].
.br
When omitting [\fIFILENAME\fR], the default format "gif" is used (use --format to overwrite), and the resulting video directly printed to standard output.
.SH EXAMPLES
.TP
.BI "giph -g " "300x200+600+200 ~/Videos/$(date +%s).png"
Records a 300x200 pixel (width x height) rectangle, that is shifted 600 pixel to the right and 200 pixel down from the top-left corner. The recording stops when either 
.B ctrl+c
is pressed, or after calling
.B giph --stop.
.br
The encoded gif will be saved in your users videos directory and has the current timestamp as a name.
.SH OPTIONS
.TP
.BR \-h ", " \-\-help
Print help and exit.
.TP
.BR \-\-stop
Finish any running giph recordings
.TP
.BR \-\-version
Print version and exit.
.TP
.BR \-v* ", " \-\-verbose ", " \-\-quiet
Defines how verbose giph will be. Omitting [\fIFILENAME\fR] will overwrite the verbosity to \fI-1\fR (quiet).  Use the following list to determine which option to use for each verbosity level:
.in +2
\(bu
.IB "-1 \fR(quiet)" " --quiet \fR - logs errors"
.br
\(bu
.IB " 0 \fR(normal) - like quiet, also displays interactive components"
.br
\(bu
.IB " 1 \fR(verbose)" " -v\fR, \fB--verbose" "\fR - like normal, also logs basic information about steps"
.br
\(bu
.IB " 2 \fR(very_verbose) " -vv "\fR - like verbose, also logs detailed information about steps"
.br
\(bu
.IB " 3 \fR(debug) " -vvv "\fR - like very_verbose, also shows background process output"
.TP
.BR \-s ", " \-\-select
Uses slop to interactively select the desired region or window to record. This uses the
.B SLOP OPTIONS
described below.
.TP
.BR \-g ", " \-\-geometry " " \fIGEOMETRY
Sets the region to record.
.TP
.BR \-w ", " \-\-window " " \fIINT
Sets the window id of the desired window to record.
.TP
.BR \-d ", " \-\-delay " " \fIINT
Sets the time in seconds to wait before the recording starts.
.TP
.BR \-t ", " \-\-timer " " \fITIMEDURATION
Sets a fixed time to record. The format is a timeduration as described in the ffmpeg documentation (https://ffmpeg.org/ffmpeg-utils.html#Time-duration). As an example, '10' would mean 10 seconds, '3:30' means 3 minutes and 30 seconds, '1:02:03' means 1 hour, 2 minutes and 3 seconds, and '5.5' means 5.5 seconds.
.TP
.BR \-f ", " \-\-framerate " \fIINT\fR (default: \fI20\fR)"
Sets the desired framerate of the recorded gif. A higher framerate will result in a larger filesize.
.TP
.BR \-\-format
Overwrites the format that should be used for the recording. The available formats are
.IR gif ", " webm ", " mp4 " and " mkv "."
While
.IR gif
is the only format that does not support audio recording.
.TP
.BR \-a ", " \-\-audio
Enables audio recording for formats that support audio.
.TP
.BR \-as ", " \-\-audio-source " \fISTRING\fR (default: '\fI0\fR')"
Define which pulseaudio source should be used for the recording. Run `pacmd list-sources` to get a list of all available sources. You can use either the index or the name of the source for this parameter. When setting this parameter, setting
.BR \-a " or " \-\-audio
can be omitted.
.TP
.BR \-m ", " \-\-microphone
Enables microphone recording for formats that support audio.
.TP
.BR \-ms ", " \-\-microphone-source " \fISTRING\fR (default: '\fIdefault\fR')"
Define which pulseaudio source should be used for the recording. Run `pacmd list-sources` to get a list of all available sources. You can use either the index or the name of the source for this parameter. When setting this parameter, setting
.BR \-m " or " \-\-microphone
can be omitted.
.TP
.BR \-y ", " \-\-notify
Uses notify-send to send an urgent notification if an error happens, or a normal notification when the final gif was saved successfully.
.SH SLOP OPTIONS
When
.BR -s " or " --select
is used, slop will be used to get geometry information. Read
.B slop(1)
for more detailed information about slop options. The following options will be passed to slop if they are set:
.TP
.BR \-b ", " \-\-bordersize " \fIFLOAT\fR (default: \fI1\fR)"
Set the selection border thickness.
.TP
.BR \-p ", " \-\-padding " \fIFLOAT\fR (default: \fI0\fR)"
Set the selection padding. This can be negative.
.TP
.BR \-to ", " \-\-tolerance " \fIFLOAT\fR (default: \fI2\fR)"
Defines how far the mouse can move after clicking while still being considered a click.
.TP
.BR \-c ", " \-\-color " \fIFLOAT,FLOAT,FLOAT,FLOAT\fR (default: \fI0.5,0.5,0.5,1\fR)"
Set the selection color as RGB or ARGB.
.TP
.BR \-r ", " \-\-shader " \fISTRING"
Set the shader to be used.
.TP
.BR \-n ", " \-\-nodecorations " \fIINT\fR (default: \fI0\fR)"
.RI "Tries to select child windows. " 0 " is off, " 1 " tries to remove decorations, " 2 " aggressively tries to remove decorations."
.TP
.BR \-l ", " \-\-highlight
.RB "Highlight the selection rectangle. This uses the color provided in " -c " or " --color "."
.TP
.BR \-k ", " \-\-nokeyboard
Disable being able to cancel the selection using the keyboard.
.TP
.BR \-o ", " \-\-noopengl
Disable graphics acceleration.
.SH SEE ALSO
.B slop(1)


================================================
FILE: src/giph
================================================
#!/usr/bin/env bash

stty -echoctl # don't print ^C when pressing ctrl+c

readonly VERSION=1.1.1

# verbosity
VERBOSITY=0

# options
SLOP=0
DELAY=0
FRAMERATE=20
AUDIO=0
AUDIO_SOURCE=0
MICROPHONE=0
MICROPHONE_SOURCE=default
FORMAT_OVERWRITE=""

function print_version() {
  echo "$VERSION"
  exit 0
}

function print_help() {
  cat << EOF
SYNOPSIS
    giph [OPTIONS] [FILENAME]

DESCRIPTION
  giph is a screen recorder that records the desktop, a window or selection and encodes it into a video file.
  The recorded video file is encoded in one of the supported formats, gif, webm, mp4 or mkv based on the file extension given in [FILENAME].
  When omitting [FILENAME], the default format "gif" is used (use --format to overwrite), and the resulting video directly printed to standard output.

OPTIONS
  -h,  --help                       Print help and exit.
       --version                    Print version and exit.
  -v*, --verbose, --quiet           Set the verbosity.
  -s,  --select                     Enable slop selection.
  -g,  --geometry=STRING            Record rectangle by geometry. (like 100x300+0+0)
  -w,  --window=INT                 Record window by id.
  -d,  --delay=INT                  Time in seconds before the recording starts.
  -t,  --timer=TIMEDURATION         Time of the recording. (e.g. 10 for 10 seconds or 1:30 for 1 minute 30 seconds)
  -f,  --framerate=INT              Set the framerate.
       --format                     Set the wanted output format. This overwrites the autodetection.
  -a,  --audio                      Enable audio recording.
  -as, --audio-source=STRING        Overwrite the default audio source.
  -m,  --microphone                 Enable microphone recording.
  -ms, --microphone-source=STRING   Overwrite the default microphone source.
  -y,  --notify                     Send notification on error or success.
       --stop                       Finish any running giph recordings.

SLOP OPTIONS
  -b, --bordersize=FLOAT                Set the selection border thickness.
  -p, --padding=FLOAT                   Set the selection padding.
  -to, --tolerance=FLOAT                Set how far the mouse can move after clicking before recrangle draws.
  -c, --color=FLOAT,FLOAT,FLOAT,FLOAT   Set the selection color.
  -r, --shader=STRING                   Set the shader to be used.
  -n, --nodecorations=INT               Set how aggresively decorations should be avoided.
  -l, --highlight                       Highlight the selection rectangle.
  -k, --nokeyboard                      Disable cancel through keypress.
  -o, --noopengl                        Disable graphics acceleration.
EOF

  exit 0
}

# log a message - (message:string, verbosity:int, timestamp:bool, stop_execution:bool, no_trailing_newline:bool)
function log() {
  [ "${2:-1}" -gt "$VERBOSITY" ] && return 0

  log=(echo -e)
  [ "$5" = true ] && log+=(-n)
  [ "$3" = true ] && log+=("\033[0;37m$(date '+%Y-%m-%d %H:%M:%S'):\033[0m")
  log+=("$1")
  "${log[@]}"

  [ "$4" = true ] && exit 1
}

function log_error() {
  notify "$1" "critical"
  log "\033[0;31mERROR:\033[0m $1" -1 "${2:-true}" true
}

function log_warning() {
  log "\033[0;33mWARNING:\033[0m $1" 0 "${2:-true}"
}

function log_success() {
  notify "$1" "normal"
  log "\033[0;32mSUCCESS:\033[0m $1" 0 "${2:-true}"
}

function log_info() {
  log "\033[0;36mINFO:\033[0m $1" 0 "${2:-true}"
}

function notify() {
  [ "$NOTIFY" = 1 ] && {
    notify=(notify-send -t 3000)
    notify+=(-u "$2")
    notify+=("giph" "$1")
    "${notify[@]}"
  }
}

if [ -z "$1" ]; then
  print_help
fi

# flag handling
while [[ "$1" == -* ]]; do
  case "$1" in
  -h|--help)
    print_help
    ;;
  --version)
    print_version
    ;;
  -v*)
    (( VERBOSITY += ${#1} - 1 ))
    ;;
  --verbose)
    (( VERBOSITY++ ))
    ;;
  --quiet)
    VERBOSITY=-1
    ;;
  --stop)
    SHOULD_STOP=true
    ;;
  -s|--select)
    SLOP=1
    ;;
  -g|--geometry)
    shift
    GEOMETRY="$1"
    ;;
  -w|--window)
    shift
    WINDOW="$1"
    ;;
  -d|--delay)
    shift
    DELAY="$1"
    ;;
  -t|--timer)
    shift
    TIMER="$1"
    ;;
  -f|--framerate)
    shift
    FRAMERATE="$1"
    ;;
  --format)
    shift
    FORMAT_OVERWRITE="$1"
    ;;
  -a|--audio)
    AUDIO=1
    ;;
  -as|--audio-source)
    shift
    AUDIO=1
    AUDIO_SOURCE="$1"
    ;;
  -m|--microphone)
    MICROPHONE=1
    ;;
  -ms|--microphone-source)
    shift
    MICROPHONE=1
    MICROPHONE_SOURCE="$1"
    ;;
  -y|--notify)
    NOTIFY=1
    ;;
  -b|--bordersize)
    shift
    SLOP_BORDERSIZE="$1"
    ;;
  -p|--padding)
    shift
    SLOP_PADDING="$1"
    ;;
  -to|--tolerance)
    shift
    SLOP_TOLERANCE="$1"
    ;;
  -c|--color)
    shift
    SLOP_COLOR="$1"
    ;;
  -r|--shader)
    shift
    SLOP_SHADER="$1"
    ;;
  -n|--nodecorations)
    shift
    SLOP_NODECORATIONS="$1"
    ;;
  -l|--highlight)
    SLOP_HIGHLIGHT=true
    ;;
  -k|--nokeyboard)
    SLOP_NOKEYBOARD=true
    ;;
  -o|--noopengl)
    SLOP_NOOPENGL=true
    ;;
  -*)
    log_error "option '$1' does not exist" false
    ;;
  esac
  shift
done

# set verbosity to -1 if the file should be printed to stdout
[ -n "$1" ] && OUTPUT_FILE="$1" || VERBOSITY=-1

case "$OUTPUT_FILE" in
    *.webm) FORMAT="webm" ;;
    *.mp4)  FORMAT="mp4" ;;
    *.mkv)  FORMAT="mkv" ;;
    *)      FORMAT="gif" ;;
esac

if [ -n "$FORMAT_OVERWRITE" ]; then
  case "$FORMAT_OVERWRITE" in
    webm|mp4|mkv|gif) FORMAT="$FORMAT_OVERWRITE";;
    *) log_error "'$FORMAT_OVERWRITE' is not a supported format."
  esac
fi

function get_geometry() {
  if [ "$SLOP" = 1 ]; then
    log "using slop to determine recording geometry" 1 true
    get_geometry_from_slop
  elif [ -n "$GEOMETRY" ]; then
    log "using provided geometry string" 1 true
    get_geometry_from_string
  elif [ -n "$WINDOW" ]; then
    log "determining geometry from provided window id" 1 true
    get_geometry_from_window_id "$WINDOW"
  else
    log_warning "no method to provide geometry given, using full desktop geometry instead"
    log "determining desktop geometry" 1 true
    get_geometry_for_desktop
  fi

  log "geometry string: '$GEOMETRY_STRING'" 2 true
  parse_geometry_string
}

function get_geometry_from_slop() {
  slop=(slop -f "%g")
  [ -n "$SLOP_BORDERSIZE" ] && slop+=(-b "$SLOP_BORDERSIZE")
  [ -n "$SLOP_PADDING" ] && slop+=(-p "$SLOP_PADDING")
  [ -n "$SLOP_TOLERANCE" ] && slop+=(-t "$SLOP_TOLERANCE")
  [ -n "$SLOP_COLOR" ] && slop+=(-c "$SLOP_COLOR")
  [ -n "$SLOP_SHADER" ] && slop+=(-r "$SLOP_SHADER")
  [ -n "$SLOP_NODECORATIONS" ] && slop+=(-n "$SLOP_NODECORATIONS")
  [ -n "$SLOP_HIGHLIGHT" ] && slop+=(-l)
  [ -n "$SLOP_NOKEYBOARD" ] && slop+=(-k)
  [ -n "$SLOP_NOOPENGL" ] && slop+=(-o)
  [ "$VERBOSITY" -lt "3" ] && slop+=(-q)

  slop_command="${slop[*]}"
  log "slop command: '$slop_command'" 2 true

  slop_value="$($slop_command)"
  [ "$?" -eq 1 ] && log_error "slop selection got canceled"

  GEOMETRY_STRING="$slop_value"
}

function get_geometry_from_string() {
  GEOMETRY_STRING="$GEOMETRY"
}

function get_geometry_from_window_id() {
  xdotool_output="$(xdotool getwindowgeometry --shell "$1" 2> /dev/null)"
  [ "$?" = 1 ] && log_error "window with id $1 does not exist"

  WIDTH=0
  HEIGHT=0

  eval "$xdotool_output"

  [[ "$X" != "-"* ]] && X="+$X"
  [[ "$Y" != "-"* ]] && Y="+$Y"

  GEOMETRY_STRING="${WIDTH}x${HEIGHT}${X}${Y}"
}

function get_geometry_for_desktop() {
  root_window_id="$(xdotool search --maxdepth 0 --class '')"
  get_geometry_from_window_id "$root_window_id"
}

function parse_geometry_string() {
  [[ "$GEOMETRY_STRING" =~ ([0-9]+)x([0-9]+)[+]?([-]?[0-9]+)[+]?([-]?[0-9]+) ]]

  width="${BASH_REMATCH[1]}"
  height="${BASH_REMATCH[2]}"
  x="${BASH_REMATCH[3]}"
  y="${BASH_REMATCH[4]}"

  [ -z "$width" ] || [ -z "$height" ] || [ -z "$x" ] || [ -z "$y" ] && {
    log_error "could not parse geometry string '$GEOMETRY_STRING'"
  }

  get_geometry_for_desktop

  [ "$x" -gt "$WIDTH" ] || [ "$((x + width))" -lt 0 ] || [ "$y" -gt "$HEIGHT" ] || [ "$((y + height))" -lt 0  ] && {
    log_error "the area to record is fully outside of the root window"
  }

  [ "$x" -lt 0 ] && {
    width="$((width + x))"
    x="0"
  }

  [ "$y" -lt 0 ] && {
    height="$((height + y))"
    y="0"
  }

  [ "$((x+width))" -gt "$WIDTH" ] && {
      ((width-="$((x + width - WIDTH))"))
  }

  [ "$((y+height))" -gt "$HEIGHT" ] && {
      ((height-="$((y + height - HEIGHT))"))
  }

  log "parsed geometry: width=$width, height=$height, x=$x, y=$y" 2 true
}

function create_temporary_directory() {
  TEMP_DIRECTORY="$(mktemp -d)"
  [ "$?" = 1 ] && log_error "could not create temporary directory"
  log "created temporary directory $TEMP_DIRECTORY" 2 true
}

function record() {
  ffmpeg=(ffmpeg -f x11grab -s "$width"x"$height" -i "$DISPLAY+$x,$y")

  if [ "$FORMAT" != "gif" ]; then
    [ "$AUDIO" = 1 ] && ffmpeg+=(-f pulse -i "$AUDIO_SOURCE")
    [ "$MICROPHONE" = 1 ] && ffmpeg+=(-f pulse -i "$MICROPHONE_SOURCE")
    [ "$AUDIO" = 1 ] && [ "$MICROPHONE" = 1 ] && ffmpeg+=(-filter_complex amerge -ac 2)
  fi

  ffmpeg+=(-vf "crop=trunc(iw/2)*2:trunc(ih/2)*2")

  [ "$VERBOSITY" -lt "3" ] && ffmpeg+=(-loglevel "quiet")
  [ -n "$TIMER" ] && [ "$TIMER" -gt 0 ] && ffmpeg+=(-t "$TIMER")

  ffmpeg+=(-r "$FRAMERATE")

  case "$FORMAT" in
    mp4|mkv)
      ffmpeg+=(-pix_fmt yuv420p)
      ffmpeg+=(-crf 15)
      ffmpeg+=("$TEMP_DIRECTORY/final.$FORMAT")
      ;;
    gif|webm|*)
      ffmpeg+=(-preset veryslow)
      ffmpeg+=(-crf 0)
      ffmpeg+=("$TEMP_DIRECTORY/lossless.mp4")
      ;;
  esac

  [ -n "$DELAY" ] && [ "$DELAY" -gt 0 ] && countdown_cli "$DELAY" "recording starts in"

  ffmpeg_command="${ffmpeg[*]}"
  log "ffmpeg command: '$ffmpeg_command'" 2 true

  "${ffmpeg[@]}" &
  FFMPEG_PID="$!"

  log "started recording video with ffmpeg" 1 true

  if [ -n "$TIMER" ] && [ "$TIMER" -gt 0 ]; then
    countdown_cli "$TIMER" "recording stops in"
  else
    stop_recording_handler_cli
  fi

  wait "$FFMPEG_PID"

  [ "$?" = 1 ] && log_error "recording video with ffmpeg failed"
  log "completed ffmpeg video recording" 1 true
}

function countdown_cli() {
  seconds="$1"
  while [ "$seconds" -ge 0 ]; do
    log "\r\033[K\033[0;36m$2:\033[0m $seconds" 0 false false true
    if [ "$seconds" -gt 0 ]; then
      sleep 1
    else
      log "\r\033[K" 0 false false true
    fi
    : "$((seconds--))"
  done
}

function stop_recording_handler_cli() {
  log_info "stop recording with \033[1;36mctrl+c\033[0m or call \033[1;36mgiph --stop\033[0m"
  trap '' INT
}

function encode() {
  log "encoding $FORMAT using ffmpeg" 1 true

  ffmpeg_encode=(ffmpeg -i "$TEMP_DIRECTORY/lossless.mp4")

  case "$FORMAT" in
    "gif")
      ffmpeg_encode+=(-vf "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse")
      ;;
    "webm")
      ffmpeg_encode+=(-c:v libvpx-vp9)
      ;;
  esac

  [ "$VERBOSITY" -lt "3" ] && ffmpeg_encode+=(-loglevel "quiet")

  ffmpeg_encode+=("$TEMP_DIRECTORY/final.$FORMAT")

  ffmpeg_encode_command="${ffmpeg_encode[*]}"
  log "ffmpeg encode command: '$ffmpeg_encode_command'" 2 true

  "${ffmpeg_encode[@]}"
  [ "$?" = 1 ] && log_error "could not encode $FORMAT from lossless recording"
}

function deliver() {
  if [ -n "$OUTPUT_FILE" ]; then
    mv "$1" "$OUTPUT_FILE" && {
      log_success "final $FORMAT saved as \"$OUTPUT_FILE\""
    }
  else
    cat "$1"
  fi
}

function delete_temporary_directory() {
  rm -r "$TEMP_DIRECTORY"
  [ "$?" = 1 ] && log_error "could not delete temporary directory"
  log "deleted temporary directory $TEMP_DIRECTORY" 2 true
}

function giph() {
  get_geometry
  create_temporary_directory
  record

  if [[ "$FORMAT" == "gif" || "$FORMAT" == "webm" ]]; then
    encode
  fi

  deliver "$TEMP_DIRECTORY/final.$FORMAT"

  delete_temporary_directory
  exit 0
}

function stop_all_recordings() {
  for pid in "$(pgrep -f "bash.+giph")"; do
    kill -INT -$pid
  done
}

if [ -n "$SHOULD_STOP" ]; then
  stop_all_recordings
else
  giph
fi

wait
Download .txt
gitextract_icb2cw67/

├── LICENSE
├── Makefile
├── README.md
├── man/
│   └── giph.1
└── src/
    └── giph
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
  {
    "path": "LICENSE",
    "chars": 1075,
    "preview": "MIT License\n\nCopyright (c) 2019 Philipp Schaffrath\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "Makefile",
    "chars": 528,
    "preview": "PREFIX ?= /usr/local\nDESTDIR ?=\nBINDIR ?= $(PREFIX)/bin\nMANDIR ?= $(PREFIX)/share/man\n\nall:\n\t@echo \"Nothing to do, try \\"
  },
  {
    "path": "README.md",
    "chars": 2921,
    "preview": "# giph\ngiph is a screen recorder that records the desktop, a window or selection and encodes it into a gif file. It prin"
  },
  {
    "path": "man/giph.1",
    "chars": 5739,
    "preview": ".TH GIPH 1 \"April 2019\" \"MIT License\" \"User Commands\"\n.SH NAME\ngiph \\- record gif from desktop, window or selection\n.SH "
  },
  {
    "path": "src/giph",
    "chars": 11908,
    "preview": "#!/usr/bin/env bash\n\nstty -echoctl # don't print ^C when pressing ctrl+c\n\nreadonly VERSION=1.1.1\n\n# verbosity\nVERBOSITY="
  }
]

About this extraction

This page contains the full source code of the phisch/giph GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (21.7 KB), approximately 7.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!