From 40e039ae2eb201194b54df93f894440144f2c87b Mon Sep 17 00:00:00 2001 From: juanlf Date: Mon, 16 Jun 2025 20:41:11 +0000 Subject: [PATCH] Subir archivos a "/" --- set-fortivpn-dns.sh | 83 +++++++++++++++ synothumb.py | 243 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 set-fortivpn-dns.sh create mode 100644 synothumb.py diff --git a/set-fortivpn-dns.sh b/set-fortivpn-dns.sh new file mode 100644 index 0000000..b8419ef --- /dev/null +++ b/set-fortivpn-dns.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# === Configuración === +VPN_NAME="FortiClient VPN" +DNS1="10.7.120.30" +DNS2="10.7.120.31" +RESOLVER_FILE="/etc/resolver/ttech.inet" +DNS_BACKUP_FILE="$HOME/.fortivpn_dns_backup" +NOTIFIER="/opt/homebrew/bin/terminal-notifier" # Ajusta según tu sistema + +# === Protección anti-ejecución múltiple === +LOCK_FILE="/tmp/set-fortivpn-dns.lock" +LOCK_TIMEOUT=10 # segundos + +if [ -f "$LOCK_FILE" ]; then + last_run=$(stat -f "%m" "$LOCK_FILE") + now=$(date +%s) + if (( now - last_run < LOCK_TIMEOUT )); then + echo "$(date): Script ejecutado recientemente. Saliendo." >> /tmp/fortivpn-dns.log + exit 0 + fi +fi + +touch "$LOCK_FILE" + +# === Función para notificaciones === +function notify() { + TITLE="$1" + MESSAGE="$2" + USER=$(stat -f "%Su" /dev/console) + sudo -u "$USER" "$NOTIFIER" -title "$TITLE" -message "$MESSAGE" +} + +# === Detectar estado de la VPN === +STATUS=$(scutil --nc status "$VPN_NAME" | head -n 1) +echo $STATUS + +if [[ "$STATUS" == "Connected" ]]; then + if [[ -f "$RESOLVER_FILE" ]]; then + exit + fi + + echo "$(date): VPN conectada." >> /tmp/fortivpn-dns.log + + # Guardar DNS originales si no están guardados + if [[ ! -f "$DNS_BACKUP_FILE" ]]; then + networksetup -getdnsservers "$VPN_NAME" > "$DNS_BACKUP_FILE" + fi + + # Aplicar nuevos DNS + networksetup -setdnsservers "$VPN_NAME" $DNS1 $DNS2 + + # Crear resolver para ttech.inet + if [[ ! -f "$RESOLVER_FILE" ]]; then + sudo /bin/mkdir -p /etc/resolver + echo "nameserver $DNS1" | sudo /usr/bin/tee "$RESOLVER_FILE" > /dev/null + echo "nameserver $DNS2" | sudo /usr/bin/tee -a "$RESOLVER_FILE" > /dev/null + fi + + notify "✅ VPN Conectada" "DNS configurado y resolver ttech.inet creado" + +else + echo "$(date): VPN desconectada." >> /tmp/fortivpn-dns.log + + # Restaurar DNS originales + if [[ -f "$DNS_BACKUP_FILE" ]]; then + ORIGINAL_DNS=$(cat "$DNS_BACKUP_FILE") + if [[ "$ORIGINAL_DNS" == "There aren't any DNS Servers set on"* ]]; then + networksetup -setdnsservers "$VPN_NAME" "Empty" + else + networksetup -setdnsservers "$VPN_NAME" $ORIGINAL_DNS + fi + rm "$DNS_BACKUP_FILE" + fi + + # Eliminar resolver + if [[ -f "$RESOLVER_FILE" ]]; then + sudo /bin/rm -f "$RESOLVER_FILE" + notify "🔌 VPN Desconectada" "DNS restaurado y resolver eliminado" + fi + + #notify "🔌 VPN Desconectada" "DNS restaurado y resolver eliminado" +fi diff --git a/synothumb.py b/synothumb.py new file mode 100644 index 0000000..aaca9ad --- /dev/null +++ b/synothumb.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +# cd; mkdir mnt_photo +# sudo mount -t {synology-ip-address}:/volume1/photo mnt_photo/ +# Author: phillips321 +# Co-authors: devdogde, sirrahd, AndrewFreemantle +# License: CC BY-SA 3.0 +# Use: home use only, commercial use by permission only +# Released: www.phillips321.co.uk +# Instructions: www.fatlemon.co.uk/synothumbs +# Dependencies: Pillow, libjpeg, libpng, dcraw, ffmpeg +# Supports: jpg, png, tif, bmp, cr2 (raw), mov, m4v, mp4 +import os,sys,threading,time,subprocess,shlex +from Queue import Queue +from PIL import Image,ImageChops #PIL is provided by Pillow +from io import StringIO + + +######################################################################### +# Settings +######################################################################### +NumOfThreads=8 # Number of threads +startTime=time.time() +imageExtensions=['.jpg','.png','.jpeg','.tif','.bmp','.cr2'] #possibly add other raw types? +videoExtensions=['.mov','.m4v','mp4'] +xlName="SYNOPHOTO_THUMB_XL.jpg" ; xlSize=(1280,1280) #XtraLarge +lName="SYNOPHOTO_THUMB_L.jpg" ; lSize=(800,800) #Large +bName="SYNOPHOTO_THUMB_B.jpg" ; bSize=(640,640) #Big +mName="SYNOPHOTO_THUMB_M.jpg" ; mSize=(320,320) #Medium +sName="SYNOPHOTO_THUMB_S.jpg" ; sSize=(160,160) #Small +pName="SYNOPHOTO_THUMB_PREVIEW.jpg" ; pSize=(120,160) #Preview, keep ratio, pad with black + +######################################################################### +# Images Class +######################################################################### +class convertImage(threading.Thread): + def __init__(self,queueIMG,badImageFileList): + threading.Thread.__init__(self) + self.queueIMG=queueIMG + self.badImageFileList=badImageFileList + + def run(self): + while True: + self.imagePath=self.queueIMG.get() + self.imageDir,self.imageName = os.path.split(self.imagePath) + self.thumbDir=os.path.join(self.imageDir,"@eaDir",self.imageName) + print (" [-] Now working on %s" % (self.imagePath)) + if os.path.isfile(os.path.join(self.thumbDir,xlName)) != 1: + if os.path.isdir(self.thumbDir) != 1: + try:os.makedirs(self.thumbDir) + except:continue + + #Following if statements converts raw images using dcraw first + if os.path.splitext(self.imagePath)[1].lower() == ".cr2": + self.dcrawcmd = "dcraw -c -b 8 -q 0 -w -H 5 '%s'" % self.imagePath + self.dcraw_proc = subprocess.Popen(shlex.split(self.dcrawcmd), stdout=subprocess.PIPE) + self.raw = StringIO(self.dcraw_proc.communicate()[0]) + self.image=Image.open(self.raw) + else: + self.image=Image.open(self.imagePath) + + ###### Check image orientation and rotate if necessary + ## code adapted from: http://www.lifl.fr/~riquetd/auto-rotating-pictures-using-pil.html + try: + self.exif = self.image._getexif() + except: + pass + + if self.exif: + + self.orientation_key = 274 # cf ExifTags + if self.orientation_key in self.exif: + self.orientation = self.exif[self.orientation_key] + + rotate_values = { + 3: 180, + 6: 270, + 8: 90 + } + + try: + if self.orientation in rotate_values: + self.image=self.image.rotate(rotate_values[self.orientation]) + except: + pass + + #### end of orientation part + + try: + self.image.thumbnail(xlSize, Image.ANTIALIAS) + self.image.save(os.path.join(self.thumbDir,xlName), quality=90) + self.image.thumbnail(lSize, Image.ANTIALIAS) + self.image.save(os.path.join(self.thumbDir,lName), quality=90) + self.image.thumbnail(bSize, Image.ANTIALIAS) + self.image.save(os.path.join(self.thumbDir,bName), quality=90) + self.image.thumbnail(mSize, Image.ANTIALIAS) + self.image.save(os.path.join(self.thumbDir,mName), quality=90) + self.image.thumbnail(sSize, Image.ANTIALIAS) + self.image.save(os.path.join(self.thumbDir,sName), quality=90) + self.image.thumbnail(pSize, Image.ANTIALIAS) + # pad out image + self.image_size = self.image.size + self.preview_img = self.image.crop((0, 0, pSize[0], pSize[1])) + self.offset_x = max((pSize[0] - self.image_size[0]) / 2, 0) + self.offset_y = max((pSize[1] - self.image_size[1]) / 2, 0) + self.preview_img = ImageChops.offset(self.preview_img, int(self.offset_x), int(self.offset_y)) # offset has to be integer, not float + self.preview_img.save(os.path.join(self.thumbDir,pName), quality=90) + except IOError: + ## image file is corrupt / can't be read / or we can't write to the mounted share + with open(self.badImageFileList, "a") as badFileList: + badFileList.write(self.imagePath + '\n') + + self.queueIMG.task_done() + +######################################################################### +# Video Class +######################################################################### +class convertVideo(threading.Thread): + def __init__(self,queueVID): + threading.Thread.__init__(self) + self.queueVID=queueVID + + def is_tool(self, name): + try: + devnull = open(os.devnull) + subprocess.Popen([name], stdout=devnull, stderr=devnull).communicate() + except OSError as e: + if e.errno == os.errno.ENOENT: + return False + return True + + def run(self): + while True: + self.videoPath=self.queueVID.get() + self.videoDir,self.videoName = os.path.split(self.videoPath) + self.thumbDir=os.path.join(self.videoDir,"@eaDir",self.videoName) + if os.path.isfile(os.path.join(self.thumbDir,xlName)) != 1: + print (" [-] Now working on %s" % (self.videoPath)) + if os.path.isdir(self.thumbDir) != 1: + try:os.makedirs(self.thumbDir) + except: + self.queueVID.task_done() + continue + # Check video conversion command and convert video to flv + if self.is_tool("ffmpeg"): + self.ffmpegcmd = "ffmpeg -loglevel panic -i '%s' -y -ar 44100 -r 12 -ac 2 -f flv -qscale 5 -s 320x180 -aspect 320:180 '%s/SYNOPHOTO:FILM.flv'" % (self.videoPath,self.thumbDir) # ffmpeg replaced by avconv on ubuntu + elif self.is_tool("avconv"): + self.ffmpegcmd = "avconv -loglevel panic -i '%s' -y -ar 44100 -r 12 -ac 2 -f flv -qscale 5 -s 320x180 -aspect 320:180 '%s/SYNOPHOTO:FILM.flv'" % (self.videoPath,self.thumbDir) + else: return False + self.ffmpegproc = subprocess.Popen(shlex.split(self.ffmpegcmd), stdout=subprocess.PIPE) + self.ffmpegproc.communicate()[0] + + # Create video thumbs + self.tempThumb=os.path.join("/tmp",os.path.splitext(self.videoName)[0]+".jpg") + if self.is_tool("ffmpeg"): + self.ffmpegcmdThumb = "ffmpeg -loglevel panic -i '%s' -y -an -ss 00:00:01 -an -r 1 -vframes 1 '%s'" % (self.videoPath,self.tempThumb) # ffmpeg replaced by avconv on ubuntu + elif self.is_tool("avconv"): + self.ffmpegcmdThumb = "avconv -loglevel panic -i '%s' -y -an -ss 00:00:01 -an -r 1 -vframes 1 '%s'" % (self.videoPath,self.tempThumb) + else: return False + try: + self.ffmpegThumbproc = subprocess.Popen(shlex.split(self.ffmpegcmdThumb), stdout=subprocess.PIPE) + self.ffmpegThumbproc.communicate()[0] + self.image=Image.open(self.tempThumb) + self.image.thumbnail(xlSize) + self.image.save(os.path.join(self.thumbDir,xlName)) + self.image.thumbnail(mSize) + self.image.save(os.path.join(self.thumbDir,mName)) + except: + self.queueVID.task_done() + continue + self.queueVID.task_done() + +######################################################################### +# Main +######################################################################### +def main(): + queueIMG = Queue() + queueVID = Queue() + try: + rootdir=sys.argv[1] + except: + print ("Usage: %s directory" % sys.argv[0]) + sys.exit(0) + + # Finds all images of type in extensions array + imageList=[] + print ("[+] Looking for images and populating queue (This might take a while...)") + for path, subFolders, files in os.walk(rootdir): + for file in files: + ext=os.path.splitext(file)[1].lower() + if any(x in ext for x in imageExtensions):#check if extensions matches ext + if "@eaDir" not in path: + if file != "Thumbs.db" and file[0] != ".": # maybe remove + imageList.append(os.path.join(path,file)) + + print ("[+] We have found %i images in search directory" % len(imageList)) + #input("\tPress Enter to continue or Ctrl-C to quit") + + #spawn a pool of threads + for i in range(NumOfThreads): #number of threads + t=convertImage(queueIMG, os.path.join(rootdir, "synothumb-bad-file-list.txt")) + t.setDaemon(True) + t.start() + + # populate queue with Images + for imagePath in imageList: + queueIMG.put(imagePath) + + queueIMG.join() + + + # Finds all videos of type in extensions array + videoList=[] + print ("[+] Looking for videos and populating queue (This might take a while...)") + for path, subFolders, files in os.walk(rootdir): + for file in files: + ext=os.path.splitext(file)[1].lower() + if any(x in ext for x in videoExtensions):#check if extensions matches ext + if "@eaDir" not in path: + if file != "Thumbs.db" and file[0] != ".": #maybe remove? + videoList.append(os.path.join(path,file)) + + print ("[+] We have found %i videos in search directory" % len(videoList)) + #input("\tPress Enter to continue or Ctrl-C to quit") + + #spawn a pool of threads + for i in range(NumOfThreads): #number of threads + v=convertVideo(queueVID) + v.setDaemon(True) + v.start() + + # populate queueVID with Images + for videoPath in videoList: + queueVID.put(videoPath) # could we possibly put this instead of videoList.append(os.path.join(path,file)) + + queueVID.join() + + endTime=time.time() + print ("Time to complete %i" % (endTime-startTime)) + + sys.exit(0) + +if __name__ == "__main__": + main()