diff --git a/flake.nix b/flake.nix index fa31080..bb126ef 100644 --- a/flake.nix +++ b/flake.nix @@ -4,28 +4,32 @@ outputs = { self, nixpkgs }@inputs: let + inherit (self) outputs; pkgs = import nixpkgs { system = "x86_64-linux"; config.allowUnfree = true; }; - download = import ./pkgs/download.nix { inherit pkgs; }; in { - packages.x86_64-linux.download = download; - nixosModules.download = - { - config, - lib, - pkgs, - ... - }: - import ./modules/download.nix { - inherit - pkgs - lib - config - download - ; - }; + packages.x86_64-linux = { + download = import ./pkgs/download.nix { inherit pkgs; }; + ffmpeg4discord = pkgs.writeScriptBin "ffmpeg4discord" (builtins.readFile ./nix/ffmpeg4discord.py); + ffmpreg = pkgs.writeScriptBin "ffmpreg" (builtins.readFile ./nix/ffmpreg.sh); + find-dup-episodes = pkgs.writeScriptBin "find-dup-episodes" ( + builtins.readFile ./nix/find-dup-episodes.sh + ); + manage-library = pkgs.writeScriptBin "manage-library" (builtins.readFile ./nix/manage-library.sh); + nextcloud-cronjob = pkgs.writeScriptBin "nextcloud-cronjob" ( + builtins.readFile ./nix/nextcloud-cronjob.sh + ); + pika-list = pkgs.writeScriptBin "pika-list" (builtins.readFile ./nix/pika-list.sh); + run = pkgs.writeScriptBin "run" (builtins.readFile ./nix/run.sh); + split-dir = pkgs.writeScriptBin "split-dir" (builtins.readFile ./nix/split-dir.sh); + stream-dl = pkgs.writeScriptBin "stream-dl" (builtins.readFile ./nix/stream-dl.sh); + sub-sync = pkgs.writeScriptBin "sub-sync" (builtins.readFile ./nix/sub-sync.sh); + package = pkgs.writeScriptBin "tasks" (builtins.readFile ./nix/tasks.sh); + update-dns = pkgs.writeScriptBin "update-dns" (builtins.readFile ./nix/update-dns.sh); + + }; }; } diff --git a/modules/base.nix b/modules/base.nix deleted file mode 100644 index 2ca1de0..0000000 --- a/modules/base.nix +++ /dev/null @@ -1,80 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -{ - options.my.scripts = lib.mkOption { - type = lib.types.attrsOf ( - lib.types.submodule { - options = { - enable = lib.mkEnableOption "Whether to enable this script"; - install = lib.mkEnableOption "Whether to install the script package"; - service = lib.mkEnableOption "Whether to enable the script service"; - name = lib.mkOption { - type = lib.types.str; - description = "Name of the script."; - }; - timer = lib.mkOption { - type = lib.types.str; - default = "*:0"; - description = "Systemd timer schedule."; - }; - description = lib.mkOption { - type = lib.types.str; - description = "Description of the service."; - }; - package = lib.mkOption { - type = lib.types.package; - description = "Package containing the executable script."; - }; - }; - } - ); - default = { }; - description = "Configuration for multiple scripts."; - }; - - config = lib.mkIf (lib.any (s: s.enable) (lib.attrValues config.my.scripts)) { - users.users.jawz.packages = lib.flatten ( - lib.mapAttrsToList ( - _name: script: lib.optional (script.enable && script.install) script.package - ) config.my.scripts - ); - - systemd.user.services = lib.mapAttrs' ( - name: script: - lib.nameValuePair "${script.name}" ( - lib.mkIf (script.enable && script.service) { - restartIfChanged = true; - inherit (script) description; - wantedBy = [ "default.target" ]; - path = [ - pkgs.nix - script.package - ]; - serviceConfig = { - Restart = "on-failure"; - RestartSec = 30; - ExecStart = "${script.package}/bin/${script.name}"; - }; - } - ) - ) config.my.scripts; - - systemd.user.timers = lib.mapAttrs' ( - name: script: - lib.nameValuePair "${script.name}" ( - lib.mkIf (script.enable && script.service) { - enable = true; - inherit (script) description; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = script.timer; - }; - } - ) - ) config.my.scripts; - }; -} diff --git a/modules/download.nix b/modules/download.nix deleted file mode 100644 index 276faae..0000000 --- a/modules/download.nix +++ /dev/null @@ -1,109 +0,0 @@ -{ - pkgs, - lib, - config, - download, - ... -}: -{ - imports = [ ./base.nix ]; - options.my.units = { - download.enable = lib.mkEnableOption "enable"; - downloadManga.enable = lib.mkEnableOption "enable"; - }; - config = { - home-manager.users.jawz = { - xdg.configFile."gallery-dl/config.json".source = ../dotfiles/gallery-dl/config.json; - services.lorri.enable = true; - programs.bash = { - shellAliases = { - dl = "download -u jawz -i"; - comic = ''dl "$(cat "$LC" | fzf --multi --exact -i)"''; - gallery = ''dl "$(cat "$LW" | fzf --multi --exact -i)"''; - }; - initExtra = '' - list_root=$XDG_CONFIG_HOME/jawz/lists/jawz - export LW=$list_root/watch.txt - export LI=$list_root/instant.txt - export LC=$list_root/comic.txt - ''; - }; - }; - systemd.user = { - services = - let - mkDownloadService = desc: execStartCmd: { - restartIfChanged = true; - description = "Downloads ${desc}"; - wantedBy = [ "default.target" ]; - path = [ - pkgs.bash - download - ]; - serviceConfig = { - TimeoutStartSec = 2000; - TimeoutStopSec = 2000; - Restart = "on-failure"; - RestartSec = 30; - ExecStart = "${download}/bin/download ${execStartCmd}"; - }; - }; - in - { - tuhmayto = lib.mkIf config.my.units.download.enable ( - mkDownloadService "tuhmayto stuff" '' - -u jawz -i https://x.com/tuhmayto/media \ - https://www.furaffinity.net/user/tuhmayto/'' - ); - "download@" = lib.mkIf (config.my.units.download.enable || config.my.units.downloadManga.enable) ( - mkDownloadService "post from multiple sources" "%I" - ); - "instagram@" = lib.mkIf config.my.units.download.enable ( - mkDownloadService "post types from instagram" "instagram -u jawz -t %I" - ); - }; - timers = - let - downloadTimer = time: delay: { - enable = true; - description = "Downloads post types from different sites"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = time; - RandomizedDelaySec = delay; - Persistent = true; - }; - }; - in - { - "instagram@stories" = lib.mkIf config.my.units.download.enable ( - downloadTimer "*-*-* 08:12:00" 120 // { } - ); - "download@main" = lib.mkIf config.my.units.download.enable ( - downloadTimer "*-*-* 06,18:02:00" 30 // { } - ); - "download@push" = lib.mkIf config.my.units.download.enable (downloadTimer "*:0/5" 30 // { }); - "download@manga" = lib.mkIf config.my.units.downloadManga.enable ( - downloadTimer "Mon,Fri *-*-* 03:08:00" 30 // { } - ); - # "download@kemono" = downloadTimer - # "*-*-1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31 18:06:00" 60 // { }; - tuhmayto = lib.mkIf config.my.units.download.enable { - enable = true; - description = "Downloads tuhmayto stuff"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "*:0/10"; - }; - }; - }; - }; - my.scripts.download = { - enable = lib.mkDefault false; - install = true; - service = false; - name = "download"; - package = download; - }; - }; -} diff --git a/nix/ffmpeg4discord.py b/nix/ffmpeg4discord.py new file mode 100644 index 0000000..c1e6f08 --- /dev/null +++ b/nix/ffmpeg4discord.py @@ -0,0 +1,138 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 + +# Imports +import os +import math + + +# Function for calculating the appropriate bitrate to use during conversion +def get_bitrate(duration, filesize, audio_br): + br = math.floor(filesize / duration - audio_br) + return br, br * 0.50, br * 1.45 + + +def encode(ffmpeg_string, output_name, fs): + os.system(ffmpeg_string) + end_size = ( + os.path.getsize( + "/dev/shm/ffmpeg/out/{output_name}".format(output_name=output_name) + ) + * 0.00000095367432 + ) + if end_size < fs: + print( + ffmpeg_string.replace("\t", "") + + "\nThe FFMPEG string above has yielded a file whose size is " + + str(end_size) + + "MB.\n{output_name} is ready for Discord.\n".format( + output_name=output_name + ) + ) + return False + else: + print( + ffmpeg_string.replace("\t", "") + + "\nThe FFMPEG string above has yielded a file whose size is " + + str(end_size) + + "MB.\n{output_name} is NOT ready for Discord, and will be re-run.\nMy bad.".format( + output_name=output_name + ) + ) + return True + + +def time_calculations(fname, length): + startstring = fname[0:2] + ":" + fname[2:4] + ":" + fname[4:6] + endstring = fname[7:9] + ":" + fname[9:11] + ":" + fname[11:13] + + try: + int(fname[0:6]) + startseconds = ( + int(fname[0:2]) * 60 * 60 + int(fname[2:4]) * 60 + int(fname[4:6]) + ) + try: + int(fname[11:13]) + endseconds = ( + int(fname[7:9]) * 60 * 60 + int(fname[9:11]) * 60 + int(fname[11:13]) + ) + duration = endseconds - startseconds + timestamped_section = f"-ss {startstring} -to {endstring}" + except: + duration = length - startseconds + timestamped_section = f"-ss {startstring}" + except: + duration = length + timestamped_section = "" + + return duration, timestamped_section + + +fname = os.listdir("/dev/shm/ffmpeg/in/")[0] +os.rename("/dev/shm/ffmpeg/in/" + fname, "/dev/shm/ffmpeg/in/" + fname.replace(" ", "")) +fname = fname.replace(" ", "") + +# ffprobe to calculate the total duration of the clip. +length = math.floor( + float( + os.popen( + "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 /dev/shm/ffmpeg/in/{fname}".format( + fname=fname + ) + ).read() + ) +) + +duration, timestamped_section = time_calculations(fname, length) + +run = True + +reso = os.getenv("reso") +codec = os.getenv("codec") +audio_br = os.getenv("audio_br") +audio_br = int(str(os.getenv("audio_br"))) +fs = float(str(os.getenv("fs"))) +target_fs = fs + +codecs = { + "vp9": { + "pass1": f"-vf scale={reso} -g 240 -threads 8 -speed 4 -row-mt 1 -tile-columns 2 -vsync cfr -c:v libvpx-vp9 -pass 1 -an", + "pass2": f"-vf scale={reso} -g 240 -threads 8 -speed 2 -row-mt 1 -tile-columns 2 -c:v libvpx-vp9 -c:a libopus -pass 2", + "output_name": "small_" + fname.replace(".mp4", ".webm"), + }, + "x264": { + "pass1": f"-vf scale={reso} -vsync cfr -c:v libx264 -pass 1 -an", + "pass2": f"-vf scale={reso} -c:v libx264 -c:a aac -pass 2 ", + "output_name": "small_" + fname, + }, + "x265": { + "pass1": f"-vf scale={reso} -c:v libx265 -vsync cfr -x265-params pass=1 -an", + "pass2": f"-vf scale={reso} -c:v libx265 -x265-params pass=2 -c:a aac", + "output_name": "small_" + fname, + }, +} + + +while run: + # Conversion to KiB + end_fs = fs * 8192 + br, minbr, maxbr = get_bitrate( + duration=duration, filesize=end_fs, audio_br=audio_br + ) + ffmpeg_string = f""" + ffpb {timestamped_section} -hwaccel cuda -i /dev/shm/ffmpeg/in/{fname} -y \ + {codecs[str(codec)]['pass1']} \ + -b:v {br}k -minrate {minbr}k -maxrate {maxbr}k \ + -f null /dev/null && \ + ffpb {timestamped_section} -hwaccel cuda -i /dev/shm/ffmpeg/in/{fname} \ + {codecs[str(codec)]['pass2']} \ + -b:a {audio_br}k -b:v {br}k -minrate {minbr}k -maxrate {maxbr}k \ + /dev/shm/ffmpeg/out/{codecs[str(codec)]['output_name']} -y + """ + + run = encode( + ffmpeg_string, output_name=codecs[str(codec)]["output_name"], fs=target_fs + ) + + if run: + fs = fs - 0.2 diff --git a/nix/ffmpreg.sh b/nix/ffmpreg.sh new file mode 100644 index 0000000..a1bcd72 --- /dev/null +++ b/nix/ffmpreg.sh @@ -0,0 +1,122 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash gum trashy fd ripgrep mediainfo + +replace_extension() { + local file_basename + file_basename=$(basename "$1") + echo "${file_basename%.*}.$2" +} + +convert_gif() { + file_newname=$(replace_extension "$1" gif) + ffpb -i "$(realpath "$1")" -vf fps=12,scale=480:-1,smartblur=ls=-0.5 "$file_newname" +} + +convert_av1() { + local file_newname + file_newname=$(replace_extension "$1" mp4) + local file_tempdest=/dev/shm/$file_newname + local file_destination + file_destination=$(dirname "$(realpath "$1")")/$file_newname + ffpb -i "$1" \ + -c:v libaom-av1 \ + -threads 12 -cpu-used 7 \ + "$file_tempdest" + trash "$1" + mv -i "$file_tempdest" "$file_destination" +} + +convert_mp4() { + local file_newname + file_newname=$(replace_extension "$1" mp4) + local file_tempdest=/dev/shm/$file_newname + local file_destination + file_destination=$(dirname "$(realpath "$1")")/$file_newname + ffpb -i "$1" \ + -c:v libx265 \ + -preset veryslow \ + "$file_tempdest" + trash "$1" + mv -i "$file_tempdest" "$file_destination" +} + +convert_discord() { + local file_newname + file_newname=$2_$(replace_extension "$1" mp4) + local dir_ram=/dev/shm/ffmpeg + mkdir -p $dir_ram/{in,out} + ffpb -hwaccel cuda -i "$(realpath "$1")" \ + -c:v h264_nvenc \ + "$dir_ram"/in/discord.mp4 + cd "$dir_ram" || exit + codec=x264 audio_br=$3 fs=$4 reso=$5 ffmpeg4discord + mv "$dir_ram"/out/small_discord.mp4 ~/"$file_newname" + command rm -rf "$dir_ram" +} + +operation=$(gum choose mp4 av1 discord nitro gif enc265) + +case $operation in + 1 | mp4) + to_convert=() + while IFS= read -r file; do + to_convert+=("$file") + done < <(fd . "$(pwd)" -tf -aL | fzf --multi -i) + for file in "${to_convert[@]}"; do + convert_mp4 "$file" + done + ;; + 2 | av1) + to_convert=() + while IFS= read -r file; do + to_convert+=("$file") + done < <(fd . "$(pwd)" -tf -aL | fzf --multi -i) + for file in "${to_convert[@]}"; do + convert_av1 "$file" + done + ;; + 3 | discord) + to_convert=() + while IFS= read -r file; do + to_convert+=("$file") + done < <(fd . "$(pwd)" -tf -aL | fzf --multi -i) + for file in "${to_convert[@]}"; do + convert_discord "$file" discord 96 8.0 "1280x720" + done + ;; + 4 | nitro) + to_convert=() + while IFS= read -r file; do + to_convert+=("$file") + done < <(fd . "$(pwd)" -tf -aL | fzf --multi -i) + for file in "${to_convert[@]}"; do + convert_discord "$file" nitro 128 50.0 "1920x1080" + done + ;; + 5 | gif) + to_convert=() + while IFS= read -r file; do + to_convert+=("$file") + done < <(fd . "$(pwd)" -tf -aL | fzf --multi -i) + for file in "${to_convert[@]}"; do + convert_gif "$file" + done + ;; + 6 | enc265) + to_convert=() + extensions=(flv m4v mpg avi mov ts mkv mp4 webm) + for ext in "${extensions[@]}"; do + while IFS= read -r file; do + if ! (mediainfo "$file" | grep Writing\ library | grep -q x265); then + to_convert+=("$file") + fi + done < <(fd . -e "$ext" -tf -aL) + done + for file in "${to_convert[@]}"; do + convert_mp4 "$file" + done + ;; + *) + echo -n "Please select a valid input" + ;; +esac diff --git a/nix/find-dup-episodes.sh b/nix/find-dup-episodes.sh new file mode 100644 index 0000000..0167eab --- /dev/null +++ b/nix/find-dup-episodes.sh @@ -0,0 +1,27 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash fd ripgrep + +root=/srv/pool/multimedia/media/Series +while IFS= read -r directory; do + while IFS= read -r season; do + season_episodes=() + while IFS= read -r episode; do + number="$(basename "$episode" | + rg --pcre2 -o "S\d+E\d+" | + rg --pcre2 -o "\d+$" | + awk '$0*=1')" + season_episodes+=($((number))) + done < <(fd . "$season" -tf -d1 \ + -E '*.srt' \ + -E '*.jpg' \ + -E '*.nfo' \ + -E '*.json') + dupe=$(printf '%s\n' "${season_episodes[@]}" | awk '!($0 in seen){seen[$0];next} 1') + if [[ -z $dupe ]]; then + continue + fi + echo "The episode $dupe is duplicated on $(basename "$season") of $(basename "$directory")" + echo "$season" + echo "_______________" + done < <(fd . "$directory" -td -d1) +done < <(fd . "$root" -td -d 1) diff --git a/nix/manage-library.sh b/nix/manage-library.sh new file mode 100644 index 0000000..6ae35ad --- /dev/null +++ b/nix/manage-library.sh @@ -0,0 +1,191 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash gum fd ripgrep eza trash-cli zip unzip + +root_directories=( + /srv/pool/multimedia/media/Library/Comics + /srv/pool/multimedia/media/Library/Manga + /srv/pool/multimedia/media/Library/Webtoons + /srv/pool/multimedia/media/Library/Espaniol/Manga +) + +newname() { + echo "$1" | sed -E "s/$2/$3/g" +} + +separator() { + gum style --foreground 7 _________________________ +} +announce_changes() { + echo "Renaming:" + gum style --foreground 1 "$1" + echo "Into:" + gum style --foreground 2 "$2" + separator +} + +rename_file() { + while IFS= read -r file; do + local original_name + original_name=$(basename "$file") + local new_name + new_name=$(newname "$(basename "$file")" "$2" "$3") + + announce_changes "$original_name" "$new_name" + command mv -n "$(dirname "$file")"/{"$original_name","$new_name"} + done < <(fd "$1" --absolute-path -tf -s "${root_directories[@]}") +} + +rename_directory() { + while IFS= read -r dir; do + local new_name + new_name=$(newname "$(basename "$dir")" "$2" "$3") + local new_dir + new_dir=$(dirname "$dir")/$new_name + + announce_changes "$dir" "$new_dir" + echo "Processing..." + if [ ! -d "$new_dir" ]; then + echo "$(basename "$new_dir") doesn't exist. Creating it." + command mkdir -p "$new_dir" + fi + if [ -d "$new_dir" ]; then + echo "$(basename "$new_dir") has been created!, moving the following files:" + eza "$dir" + fd . "$dir" -x mv -n {} "$(realpath "$new_dir")" + fi + separator + done < <(fd "$1" --absolute-path -td -s "${root_directories[@]}") +} + +rename_numbered_files() { + while IFS= read -r file; do + local original_name + original_name=$(basename "$file") + local new_name + + new_name=$(echo "$original_name" | sed -E 's/(.*) - 0*([[:digit:]]+)(\.cbz)/\1 #\2\3/') + + if [[ "$new_name" != "$original_name" ]]; then + announce_changes "$original_name" "$new_name" + command mv -n "$(dirname "$file")"/{"$original_name","$new_name"} + fi + done < <(fd --absolute-path -tf -e cbz '\-[[:space:]]0*[[:digit:]]+' "${root_directories[@]}") +} + +# Check directory existence +for dir in "${root_directories[@]}"; do + if [ -d "$dir" ]; then + continue + fi + echo "directory doesn't exist... creating $dir" + mkdir -vp "$dir" +done + +# Fix numbered issues (For migrating from old directory) +rename_numbered_files + +# Capitalize Special words +words=(special tpb full annual) +Words=(Special TPB Full Annual) +counter=0 +for word in "${words[@]}"; do + while IFS= read -r file; do + new_name=$(newname "$(basename "$file")" "$word" "${Words[$counter]}") + echo "Inproper capitalization of the word" + gum style --foreground 1 "$word" + echo "adjusting it into" + gum style --foreground 2 "${Words[$counter]}" + announce_changes "$(basename "$file")" "$new_name" + command mv -n "$(dirname "$file")"/{"$(basename "$file")","$new_name"} + done < <(fd "$word" --absolute-path -tf -s "${root_directories[@]}") + counter=$((counter + 1)) +done + +# Rename Year files +# set regex_year_grep "\([[:digit:]]{4}\)" +# set regex_year_string "(\()(\d{4})(\))" +# rename_directory $regex_year_grep $regex_year_string \$2 +# rename_file $regex_year_grep $regex_year_string \$2 + +# Rename #_ downloads +regex_hashtag="#_" +rename_directory $regex_hashtag $regex_hashtag "#" +rename_file $regex_hashtag $regex_hashtag "#" + +# Rename ~ to : +# rename_directory " ~ " " ~ " ": " +# rename_file " ~ " " ~ " ": " + +rename_keywords() { + # Followed by digit + local regex_digit_fd="$1 \d+" + local regex_digit="($1 )([[:digit:]]+)" + rename_directory "$regex_digit_fd" "$regex_digit" "\1#\2" + rename_file "$regex_digit_fd" "$regex_digit" "\1#\2" + # Without digit + regex="#$1" + rename_directory "$regex" "$regex" "$1" + rename_file "$regex" "$regex" "$1" +} + +rename_keywords TPB +rename_keywords Special +rename_keywords Annual + +# Rename #Full +rename_directory " #Full" " #Full" "" +rename_file " #Full" " #Full" "" + +# Rename double space +rename_directory " " " " " " +rename_file " " " " " " + +# Fix names +wrongnames=( + "Transformers: Spotlight" + "Dr. Stone" + i-dont-want-this-kind-of-hero + pure-of-heart + scoob-and-shag + stick-n-poke + "Houseki no Kuni" + "Gantz E" + "Gantz G" +) +rightname=( + "Transformers Spotlight:" + "Dr. STONE" + "I DON'T WANT THIS KIND OF HERO" + "Pure of Heart" + "Scoob and Shag" + "Stick n' Poke" + "Land of the Lustrous" + "Gatz:E" + "Gantz:G" +) +counter=0 +for wrongname in "${wrongnames[@]}"; do + rename_directory "$wrongname" "$wrongname" "${rightname[$counter]}" + rename_file "$wrongname" "$wrongname" "${rightname[$counter]}" + counter=$((counter + 1)) +done + +# Merge TPB (Part X) files +while IFS= read -r file; do + new_name=$(newname "$(basename "$file" .cbz)" "TPB \(Part [[:digit:]]+\)" TPB) + extract_dir=$(realpath "$(dirname "$file")"/"$new_name") + if [ ! -d "$extract_dir" ]; then + mkdir -p "$extract_dir" + fi + unzip "$file" -d "$extract_dir"/"$(basename "$file" .cbz)" + cd "$extract_dir" || exit + zip -r "$(realpath "$(dirname "$file")")"/"$new_name"\.cbz ./ + trash "$file" + trash "$extract_dir"/"$(basename "$file" .cbz)" +done < <(fd "Part \d+" --absolute-path -tf -s "${root_directories[@]}") + +fd . --absolute-path -tf -td "${root_directories[@]}" -x chown jawz:kavita {} +fd . --absolute-path -tf "${root_directories[@]}" -x chmod 664 {} +fd . --absolute-path -td "${root_directories[@]}" -x chmod 775 {} + +fd . --absolute-path -td -te "${root_directories[@]}" -x rmdir {} diff --git a/nix/nextcloud-cronjob.sh b/nix/nextcloud-cronjob.sh new file mode 100644 index 0000000..1bcbdd2 --- /dev/null +++ b/nix/nextcloud-cronjob.sh @@ -0,0 +1,59 @@ +#!/run/current-system/sw/bin/bash + +# Cron tasks +if type /run/current-system/sw/bin/nextcloud-occ 2>/dev/null; then + /run/current-system/sw/bin/nextcloud-occ preview:pre-generate + # /run/current-system/sw/bin/nextcloud-occ face:background_job -t 900 +fi + +# Sync GDL stuff +root=/srv/pool/scrapping + +cd $root || exit +set -- Aqp Ghekre +for user in "$@"; do + originDir=$root/$user + destDir=/srv/pool/nextcloud/$user/files/Requested + destDirDup=/srv/pool/nextcloud/$user/files/RequestedDupePlzCheckNDel + if [ ! -d "$destDir" ]; then + echo "$destDir does not exist, creating..." + mkdir -p "$destDir" + fi + cd "$originDir" || exit + find . -type f -not -name '*.part' | while read -r file; do + destination=$destDir/"$(echo "$file" | sed "s/^\.\///")" + destinationDup=$destDirDup/"$(echo "$file" | sed "s/^\.\///")" + + if [ ! -f "$destination" ]; then + echo "Safe to move $(basename "$file")" + if [ ! -d "$(dirname "$destination")" ]; then + echo "Creating parent directory..." + mkdir -p "$(dirname "$destination")" + fi + mv -n "$file" "$destination" + else + echo "Duplicated encountered $(basename "$file")" + if [ ! -d "$(dirname "$destinationDup")" ]; then + echo "Creating parent directory..." + mkdir -p "$(dirname "$destinationDup")" + fi + mv -n "$file" "$destinationDup" + fi + + done + + find ./ -mindepth 1 -type d -empty -delete + + chown 987:988 -R "$destDir" + find "$destDir" -type d -exec chmod -R 755 {} \; + find "$destDir" -type f -exec chmod -R 644 {} \; + + if [ -d "$destDirDup" ]; then + chown 987:988 -R "$destDirDup" + find "$destDirDup" -type d -exec chmod -R 755 {} \; + find "$destDirDup" -type f -exec chmod -R 644 {} \; + fi + if type /run/current-system/sw/bin/nextcloud-occ 2>/dev/null; then + /run/current-system/sw/bin/nextcloud-occ files:scan --all + fi +done diff --git a/nix/pika-list.sh b/nix/pika-list.sh new file mode 100644 index 0000000..ef3b2d6 --- /dev/null +++ b/nix/pika-list.sh @@ -0,0 +1,51 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash fd borgbackup gum ripgrep + +BORG_PASSPHRASE=$(gum input --password --placeholder "Type borg password") +export BORG_PASSPHRASE + +d_root=$HOME/pika +f_string=home/jawz/.config/jawz/lists/jawz/watch.txt +d_borg=/srv/pool/backups/pika/lists + +while IFS= read -r repo; do + IFS=" " read -r -a array <<<"$repo" + repo_id="${array[0]}" + mkdir -vp "$d_root/$repo_id" && cd "$d_root/$repo_id" || exit + borg extract $d_borg::"$repo_id" $f_string + cat "$d_root/$repo_id/$f_string" >>"$d_root/master" +done < <(borg list "$d_borg") + +cd "$HOME" || exit + +sort -u "$d_root/master" -o "$d_root/sorted" +sort -u "$LW" -o "$LW" + +echo "Current $(wc -l <"$LW") archived $(wc -l <"$d_root/sorted")" + +echo "Missing lines:" +diff "$d_root/sorted" "$LW" + +# look for duped lines with different casing +echo "Duplicated lines:" +while IFS= read -r line; do + if ! [ "$line" == "${line,,}" ]; then + if rg "${line,,}" <"$LW"; then + echo "$line" + fi + fi +done <"$LW" + +# delete pika backups +if gum confirm "Limpiar pika?"; then + command rm -rf "$d_root" + while IFS= read -r repo; do + IFS=" " read -r -a array <<<"$repo" + repo_id="${array[0]}" + gum spin --spinner dot --title "Cleaning $repo_id..." -- borg delete $d_borg::"$repo_id" + done < <(borg list "$d_borg") +else + echo "Canceled, no files deleted" +fi +gum spin --spinner dot --title "Cleaning $repo_id..." -- borg compact "$d_borg" +gum spin --spinner dot --title "Cleaning $repo_id..." -- borg compact /srv/pool/backups/pika/home diff --git a/nix/run.sh b/nix/run.sh new file mode 100644 index 0000000..1028f37 --- /dev/null +++ b/nix/run.sh @@ -0,0 +1,44 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash gnome.zenity rmlint git gum xclip + +if [ -n "$1" ]; then + operation=$1 +else + operation=$(gum choose rmlint download git) +fi + +case $operation in + # onlyfans) + # source ~/Development/Python/onlyfans/bin/activate.fish + # python ~/Development/Git/OnlyFans/start_ofd.py + # deactivate + rmlint) + rmlint -g --types="duplicates" \ + --config=sh:handler=clone \ + /srv/pool/ + ;; + download) + ENTRY=$(zenity --entry --width=250 --title "Push Manager" \ + --text="Verify the following entry is correct" \ + --add-entry="Clipboard:" --entry-text "$(xclip -o -sel clip)") + if [ -n "$ENTRY" ]; then + # kgx -e "download -u jawz -i '$ENTRY'" + kgx -e "ssh miniserver ""download -u jawz -i ""$ENTRY"" "" " + else + zenity --error --width=250 \ + --text "Please verify and try again" + fi + ;; + git) + git_dir=$HOME/Development/Git + while IFS= read -r repo; do + if ! [ -d "$repo/.git" ]; then + continue + fi + cd "$repo" || exit + gum style --foreground 2 "Updating $(basename "$repo")" + git fsck --full + git pull + done < <(fd . "$git_dir" -td --absolute-path -d 1) + ;; +esac diff --git a/nix/split-dir.sh b/nix/split-dir.sh new file mode 100644 index 0000000..834f313 --- /dev/null +++ b/nix/split-dir.sh @@ -0,0 +1,33 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash fd + +before_count=$(fd -tf | wc -l) +i=0 + +for file in $(fd -d1 -tf -E '*.mp4' -E '*.webm'); do + dir_name=$(basename "$(pwd)")_$(printf %03d $((i / $1 + 1))) + mkdir -p "$dir_name" + mv -i "$file" "$(realpath "$dir_name")"/ + i=$((i + 1)) +done + +for file in $(fd -d1 -tf -e webm); do + mkdir -p webm + mv -i "$file" "$(realpath webm)"/ +done + +for file in $(fd -d1 -tf -e mp4); do + mkdir -p videos + mv -i "$file" "$(realpath videos)"/ +done + +after_count=$(fd -tf | wc -l) + +if [[ "$before_count" == "$after_count" ]]; then + echo "No file count differences" +else + echo "Before count: $before_count" + echo "After count: $after_count" +fi +sleep 10 +exit diff --git a/nix/stream-dl.sh b/nix/stream-dl.sh new file mode 100644 index 0000000..8844076 --- /dev/null +++ b/nix/stream-dl.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash -p bash yt-dlp + +minutes=5 +time_alive=60 +sleep_time=$((minutes * 60)) +loops=$((time_alive / (sleep_time / time_alive))) + +re="[[:space:]]+" +echo $1 +if [[ $1 =~ $re ]]; then + read -ra arr <<<"$1" + url="https://picarto.tv/${arr[0]}" +else + url="https://chaturbate.com/$1" +fi + +save_dir=/srv/pool/glue/stream-dl +if [ ! -d "$save_dir" ]; then + mkdir -p "$save_dir" +fi +cd $save_dir || exit + +for i in $(seq 1 1 "$loops"); do + waiting_time=$(((i * sleep_time) / time_alive)) + yt-dlp --hls-use-mpegts --prefer-ffmpeg -o '%(title)s.%(ext)s' "$url" + echo "sleeping for $sleep_time seconds… been waiting for $waiting_time minutes" + sleep $sleep_time +done diff --git a/nix/sub-sync.sh b/nix/sub-sync.sh new file mode 100755 index 0000000..34e9af5 --- /dev/null +++ b/nix/sub-sync.sh @@ -0,0 +1,186 @@ +#!/run/current-system/sw/bin/bash + + +# nix-shell -i bash -p bash fd ripgrep file alass ffmpeg gum + +MEDIA_ROOT=("/srv/pool/multimedia/media/Series" "/srv/pool/multimedia/media/Movies") +REPLACE_DIR="/srv/pool/multimedia/media" +SUBTITLE_MIRROR="/srv/pool/multimedia/backups/subtitles" +RAM_SUB="/dev/shm/sub.srt" + +# BACKUPS SUBTITLES +backup_subtitles() { + while IFS= read -r subtitle; do + echo "backing up $subtitle" + dest_dir="$(dirname "$subtitle")" + dest_dir="${dest_dir/$REPLACE_DIR/$SUBTITLE_MIRROR}" + mkdir -p "$dest_dir" + cp "$subtitle" "${subtitle/$REPLACE_DIR/$SUBTITLE_MIRROR}" + done < <(fd . -tf -e srt --absolute-path "${MEDIA_ROOT[@]}") +} + +clean_up() { + while IFS= read -r directory; do + echo "cleaning up $directory" + subtitles=() + mapfile -d $'\0' subtitles < <(fd . "$directory" -e srt -tf -d 1 -0) + + if [ "${#subtitles[@]}" -lt 2 ]; then + continue + fi + + unset base_subtitle + unset subtitles_group + for subtitle in "${subtitles[@]}"; do + group=() + mapfile -d $'\0' group < <(fd --fixed-strings \ + "$(basename "$subtitle" .srt)" "$directory" \ + -d 1 -tf -0 -e srt) + for key in "${!group[@]}"; do + if ! echo "${group[$key]}" | rg -P '\.\d{1,2}(\.\w+(-\w+)?)?\.srt' -q; then + unset "group[$key]" + continue + fi + if [ -z "${group[$key]}" ]; then + continue + fi + echo "removing $(basename "$subtitle")" + rm "$subtitle" + done + done + done < <(fd . -td --absolute-path "${MEDIA_ROOT[@]}") +} + +rename_languages() { + while IFS= read -r file; do + base=$(basename "$file" .eng.srt) + dir=$(dirname "$file") + echo "renaming sub $base" + mv "$file" "$dir/$base.$2.srt" + done < <(fd . -tf --absolute-path "${MEDIA_ROOT[@]}" -e "$1.srt") +} + +sync_subtitles() { + while IFS= read -r directory; do + echo "scanning for sync $directory" + while IFS= read -r subtitle; do + echo "processing $subtitle" + video=() + extension=$(echo "$subtitle" | rg -oP "(\.\w+(-\w+)?)?\.srt") + basename="$(basename "$subtitle" "$extension")" + mapfile -d $'\0' video < <(fd "$basename" \ + "$directory" --fixed-strings \ + -e mkv -e mp4 -e avi -e webm -tf -d 1 -0) + + # skips directory if it contains more than 1 video file + # should never get triggered + if [ "${#video[@]}" -gt 1 ]; then + basename "$(dirname "$directory")" + echo "$(basename "$directory") has many video files: ${#video[@]}" + continue + fi + + # update subtitle in ram + if [ -e "$RAM_SUB" ]; then + rm "$RAM_SUB" + fi + cp "$subtitle" "$RAM_SUB" + + if [ ! -e $RAM_SUB ] && [ ! -e "${video[0]}" ]; then + continue + fi + echo "processing...$subtitle" + alass-cli "${video[0]}" "$RAM_SUB" "$subtitle" + + done < <(fd . "$directory" -tf -e srt -d 1 --newer "$1") + done < <(fd . -td --absolute-path "${MEDIA_ROOT[@]}") +} + +find_dupes() { + while IFS= read -r directory; do + videos=() + mapfile -d $'\0' videos < <(fd . \ + "$directory" -tf -d 1 -0 \ + -e mkv -e mp4 -e avi -e webm) + + if [ "${#videos[@]}" == 0 ]; then + if [[ "$directory" != *"Season"* ]]; then + continue + fi + echo "NO FILES ERROR: $directory" + fi + + if [ "${#videos[@]}" == 1 ]; then + continue + fi + + if [ "${#videos[@]}" -gt 1 ]; then + if [[ "$directory" == *"media/Movies"* ]]; then + echo "Movie directory has more than a movie" + continue + fi + for episode in "${videos[@]}"; do + episode_number="$(echo "$episode" | + rg -oP "S\d+E\d+(-E\d+)? ")" + episode_files="$( + fd "$episode_number" "$directory" --fixed-strings \ + -tf -d 1 \ + -e mkv -e mp4 -e avi -e webm | wc -l + )" + if [ "$episode_files" == 1 ]; then + continue + fi + echo ____________________________ + echo "The episode $episode_number is repeated on" + echo "$directory" + fd "$episode_number" "$directory" --fixed-strings \ + -tf -d 1 \ + -e mkv -e mp4 -e avi -e webm + done + fi + + done < <(fd . -td --absolute-path "${MEDIA_ROOT[@]}") +} + +fd . /srv/pool/multimedia/media/Series/ --owner jawz -x chown sonarr:piracy {} +fd . /srv/pool/multimedia/media/Movies/ --owner jawz -x chown radarr:piracy {} +fd . "${MEDIA_ROOT[@]}" -td -x chmod 775 {} +fd . "${MEDIA_ROOT[@]}" -tf -x chmod 664 {} + +rename_languages eng en +rename_languages spa es +rename_languages mx es_MX + +if [ -n "$1" ]; then + operation=$1 +else + operation=$(gum choose backup clean sync all) +fi +if [ -n "$2" ]; then + start_time=$2 +else + start_time="$(date '+%Y-%m-%d') 00:00:00" +fi + +case $operation in + backup) + backup_subtitles + ;; + clean) + clean_up + ;; + sync) + sync_subtitles "$start_time" + ;; + dupe) + find_dupes + ;; + all) + echo "backing up" + backup_subtitles + echo "cleaning up" + clean_up + echo "syncing" + sync_subtitles "$start_time" + ;; +esac diff --git a/nix/tasks.sh b/nix/tasks.sh new file mode 100755 index 0000000..a54f8e2 --- /dev/null +++ b/nix/tasks.sh @@ -0,0 +1,165 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i bash -p bash trashy fd ripgrep file + +directories=("$HOME/Pictures/To Organize/" "$HOME/Downloads/" "$HOME/Downloads/cache") + +replace_extension() { + local file_basename + file_basename=$(basename "$1") + echo "${file_basename%.*}.$2" +} + +generate_random_number() { + local min=0 + local max=9999999999 + printf "%010d\n" $((min + RANDOM % max)) +} + +test_name() { + local random_number + random_number=$(generate_random_number) + while (($(fd "$random_number"* "$HOME/Pictures/" "$HOME/Downloads/" -tf | wc -l) > 0)); do + echo "Conflicts found, generating a new filename" + random_number=$(generate_random_number) + echo "$random_number" + done + echo "$random_number" +} + +while IFS= read -r file; do + regex_str='source|tenor|media|duckduckgo\.com|giphy|' + regex_str+='(? 0)); then + while IFS= read -r file; do + date=$(stat -c "%y" "$file" | rg -o "\d{4}-\d{2}-\d{2}") + year=$(echo "$date" | rg -o "\d{4}") + month=$(echo "$date" | rg -o "\d{4}-\d{2}" | rg -o --pcre2 "(?<=-)\d{2}") + parent_dir=$(dirname "$(realpath "$file")") + dest_dir=$(realpath "$parent_dir")/$year/$month + echo "Moving screenshot $(basename "$file") into $dest_dir" + mkdir -vp "$dest_dir" + command mv -n "$file" "$dest_dir/" + done < <(fd . "${classify_directories[@]}" --absolute-path -tf -d 1) +fi + +# Where steam screenshots are stored, may need to replace with ur ID +dir_steam=$XDG_DATA_HOME/Steam/userdata/107446271/760/remote +declare -A games +# Insert here new games, put between [] the ID of the game +# You can find it by visiting the $dir_steam directory +# the ID is simply the name of the folder in there. +games+=( + [386360]=Smite + [960090]="Bloons Tower Defense 6" + [648800]=Raft + [262060]="Darkest Dungeon" + [234140]="Mad Max" + [433340]="Slime Rancher" + [1190460]="Death Stranding" + [1850570]="Death Stranding" + [440900]="Conan Exiles" + [679110]="Werewolf Apocalypse" + [2221490]="The Division 2" +) + +for key in "${!games[@]}"; do + # Modify this to store your screenshots somewhere else + dir_dest=$(realpath "$HOME/Pictures/Screenshots/Games")/${games[$key]} + dir_game=$(realpath "$dir_steam")/$key/screenshots + # If there are not screenshots currently stored, why bother lol + if ! [[ -d $dir_game ]]; then # + continue + fi + # If screenshots exist however... + if ! (($(fd . "$dir_game" -d 1 -tf | wc -l) > 0)); then + continue + fi + # Create destination directory + mkdir -vp "$dir_dest" + echo "Moving ${games[$key]} screenshots..." + fd . "$dir_game" -d 1 -tf -x mv -n {} "$dir_dest"/ + # Delete thumnnails + echo "Deleting ${games[$key]} thumbnails..." + rm -rf "$dir_game"/thumbnails +done +# Clearing up empty directories +fd . "$dir_steam" -td -te -x trash {} + +cyberpunk_dir=$HOME/Games/gog/cyberpunk-2077/drive_c/users/jawz/Pictures/"Cyberpunk 2077" +if [[ -d $cyberpunk_dir ]]; then + while IFS= read -r file; do + echo "Moving cyberpunk screenshots $(basename "$file")" + command mv -n "$file" "$HOME/Pictures/Screenshots/Games/Cyberpunk 2077/" + done < <(fd . "$cyberpunk_dir" -tf) +fi + +proton_dir=$HOME/.steam/steam/compatibilitytools.d +if [[ -d "$proton_dir" ]]; then + while IFS= read -r protonver; do + lutrisdir=$XDG_DATA_HOME/lutris/runners/wine/$(basename "$protonver") + if [ -d "$lutrisdir" ] && [ -L "$lutrisdir" ]; then + continue + fi + echo "Symlink $lutrisdir doesn't exist, creating link..." + ln -s "$(realpath "$protonver")"/files "$lutrisdir" + done < <(fd . "$proton_dir" -d 1 -td) +fi +fd . "$XDG_DATA_HOME/lutris/runners/wine" -d1 -tl -Lx trash {} + +while IFS= read -r file; do + ext=$(file --mime-type "$file" | rg -o '\w+$') + correct_ext=${ext,,} + filename=$(basename -- "$file") + current_ext="${filename##*.}" + filename="${filename%.*}" + if ! echo "$correct_ext" | rg -q 'jpe|jpg|jpeg|png|gif|webp'; then + continue + fi + if [ "$current_ext" == "$correct_ext" ]; then + continue + fi + echo "The file $(basename "$file")" \ + "will be renamed, the propper extension is $correct_ext" + new_name="$filename".$correct_ext + if command mv -n "$(dirname "$file")"/{"$(basename "$file")","$new_name"}; then + continue + fi + + file_hash="$(sha256sum "$file" | gawk '{ print $1 }')" + if ! echo "$file_hash $(dirname "$file")/$new_name" | sha256sum -c; then + continue + fi + echo "deleting duplicated: $file" + rm "$file" +done < <(fd . "${directories[@]}" -d 1 -tf) + +files_home_clean=(.pki HuionCore.pid DriverUI.pid huion.log) +for file in "${files_home_clean[@]}"; do + file=$HOME/$file + if [ ! -e "$file" ]; then + continue + fi + rm -rf "$file" +done diff --git a/nix/update-dns.sh b/nix/update-dns.sh new file mode 100755 index 0000000..c720956 --- /dev/null +++ b/nix/update-dns.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash -p bash curl + +function header { + echo ============================================= + echo "$1" + echo ============================================= +} + +ip=$(curl -s -X GET https://checkip.amazonaws.com) +header "$ip" +header NAMECHEAP + +hostname=@ +domain=rotehaare.art +password="$PASSROTE" +base="https://dynamicdns.park-your-domain.com/update" + +if host "$domain" 1.1.1.1 | grep "has address" | grep "$ip"; then + echo "$domain is currently set to $ip; no changes needed" + exit +fi +echo updating "$domain" +host="host=$hostname" +domain="domain=$domain" +password="password=$password" +curl "$base?$host&$domain&$password&ip=$ip" +echo diff --git a/scripts.nix b/scripts.nix new file mode 100644 index 0000000..ce7f3d4 --- /dev/null +++ b/scripts.nix @@ -0,0 +1,11 @@ +{ lib, ... }: +{ + imports = + let + scriptFiles = builtins.filter (file: builtins.match ".*\\.nix" file != null && file != "base.nix") ( + builtins.attrNames (builtins.readDir ./scripts) + ); + in + map (file: ./scripts/${file}) scriptFiles; + my.units.stream-dl.enable = lib.mkDefault false; +}