Kodi Shell Script: Find videos missing a thumbnail

Well, compared to the previous script, this one is a short one. It’ll find all Matroska containers lacking a corresponding thumbnail (-thumb.jpg or .tbn) file. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/opt/bin/bash # Find all episodes/movies missing a thumb file MKV="$( find . -name "*.mkv" | sed "s,./,," | sort )" echo "These videos are missing a thumbnail file:" echo "" for mkv in $MKV; do basename="${mkv%.*}" # Check if there is a <xbmc11 thumbnail file if [ -f "$basename.tbn" ] ; then : elif [ -f "$basename-thumb.jpg" ] ; then : else echo " - $basename.mkv" fi done echo

April 6, 2015 · 1 min · 115 words · christian

Sickbeard Shell Script: Fix TV episodes name

Well, I use SickBeard. And sometimes (very often actually) the names are rather screwed up…. So I wrote myself a script, that’ll fix most episode errors (I’ve caught so far …). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 #!/opt/bin/bash OPTS="$@" [ "$( cat /etc/distribution 2>/dev/null )" == "OpenELEC" ] && openelec=1 || openelec=0 [ "$( mount | /opt/bin/grep "$( echo $PWD | /opt/bin/sed "s,/tvshows,," )" | awk '{ print $5 }' )" == "cifs" ] && cifs=1 || cifs=0 if [ $openelec -eq 0 -a $cifs -eq 0 ] ; then # Fix permissions chown -R nobody.users "$PWD" /opt/bin/findutils-find "$PWD" -type f ! -perm 0664 -exec chmod 0664 {} \; /opt/bin/findutils-find "$PWD" -type d ! -perm 0775 -exec chmod 0775 {} \; fi EXTENSIONS=".avi .mp4 .mkv .srt .tbn .nfo .xml -thumb.jpg" # Needs renaming: PATTERN="WEB.DL,WEB-DL Web-Dl,WEB-DL AVC.AC3,DD5.1.H.264 .AC3.PSIV,-PSIV DD.5.1,DD5.1 DD5-1,DD5.1 Dd5.1,DD5.1 DD.2.0,DD2.0 WEB-DLAAC2,WEB-DL.AAC2 H.264.DD5.1,DD5.1.H.264 AAC.2.0,AAC2.0 DD5.1.AAC2.0,DD5.1 WEB-DL-pcsyndicate,WEB-DL.DD5.1.H.264-pcsyndicate x264,H.264 X264,H.264 h264,H.264 H264,H.264 Forever.S0,Forever.2014.S0 H-264,H.264 h.264,H.264 DD5.1-H.264,DD5.1.H.264 .KiNGS,-KiNGS -KINGS,-KiNGS .TB,-TB .BS,-BS .~DG2~, .~DG~, .CtrlHD,-CtrlHD 1x,S01E .ECI,-ECI .NFHD,-NFHD .POD,-POD \.NTb,\-NTb .DNR,-DNR .pcsyndicate,-pcsyndicate German.DD20.Synced.DL.720p.iTunesHD.AVC,720p.WEB-DL.DD2.0.DL.H.264 -ss,-SS .Reaperza,-Reaperza Grey's.Anatomy,Greys.Anatomy Five-0,Five.0 Hawaii.Five.0.2010\.S0,Hawaii.Five.0.S0 WEBRip,WEB-DL WEB-DL.H.264.AAC2.0,WEB-DL.AAC2.0.H.264 Hell.On.Wheels,Hell.on.Wheels Mythbusters,MythBusters Dont.Trust.The.B----.In.Apartment.23,Dont.Trust.The.B.In.Apartment.23 Dont.Trust.the.Bitch.in.Apartment.23,Dont.Trust.The.B.In.Apartment.23 Dont.Trust.the.B.in.Apartment.23,Dont.Trust.The.B.In.Apartment.23 Rizzoli.&.Isles,Rizzoli.and.Isles Revolution.2012,Revolution Orange.Is.The.New.Black,Orange.Is.the.New.Black Castle.S,Castle.2009.S /Agents.of.S.H.I.E.L.D.,/Marvels.Agents.Of.S.H.I.E.L.D. Marvel.Agents.Of.SHIELD,Marvels.Agents.Of.S.H.I.E.L.D. Marvel.Agents.Of.S.H.I.E.L.D..S,Marvels.Agents.Of.S.H.I.E.L.D.S Marvel.Agents.Of.S.H.I.E.L.D.S,Marvels.Agents.Of.S.H.I.E.L.D.S Marvels.Agents.Of.S.H.I.E.L.D..S,Marvels.Agents.Of.S.H.I.E.L.D.S Marvels.Agents.of.S.H.I.E.L.D.,Marvels.Agents.Of.S.H.I.E.L.D. Rizzoli.Isles,Rizzoli.and.Isles The.Bridge.S,The.Bridge.US.S Last.Man.Standing.US,Last.Man.Standing.2011 The.Americans.S,The.Americans.2013.S Person.Of.Interest,Person.of.Interest The.Tomorrow.People.S0,The.Tomorrow.People.US.S0 The.Code.AU,The.Code.2014 How.to.Get.Away.With.Murder,How.To.Get.Away.With.Murder How.to.Get.Away.with.Murder,How.To.Get.Away.With.Murder How.To.Get.Away.with.Murder,How.To.Get.Away.With.Murder Izombie,iZombie -SiCKBEARD,.720p.WEB-DL.DD5.1.H.264 DL.DD5.1.WEB-DL,WEB-DL.DD5.1.DL XIII.The.Series.2011,XIII.2011" FILEEXT="\\.nfo\\. \\.par2\\." # Find files containing spaces and rename them according to the scene rules for ext in $EXTENSIONS; do [ "$ext" != ".srt" ] && \ /opt/bin/find . -name "* *$ext" -type f -exec sh -c ' fp="${0%/*}" fn="${0##*/}" fn="$( echo $fn | /opt/bin/sed -e "s,\!,," )" fn="$( echo $fn | /opt/bin/egrep -oi "[A-Z][A-Za-z0-9.-]+.$ext" | sort -u | tail -n1 )" echo "Enforcing naming scheme for $0" mv "$0" "$fp/$fn" read -t 1 line </dev/tty ' {} ';' done # Build the list of replacements. Do it here, since we need to # do it only once, and not for each file. for pat in $PATTERN; do set -- `echo $pat | tr , \ ` REN="$REN -e ""s,$1,$2,g""" done for pat in $FILEEXT; do REN="$REN -e ""s,${pat},,g""" done REN="$REN -e ""s/[()]//g""" # Main loop starts here. Only handle files with the specified extensions. for ext in $EXTENSIONS; do REGEX="$REGEX|$ext" done REGEX="$( echo $REGEX | sed "s,|,," )" MAIN_REN=$REN for file in $( /opt/bin/find . -regextype posix-egrep -type f -regex ".*($REGEX)" ! -wholename '*tvshow*' ! -wholename '*season*' ! -wholename '*actors' | sort ); do OLD="$file" NEW="$file" REN="$MAIN_REN" if [ "$( echo $file | /opt/bin/egrep "\.(REPACK|REREPACK|PROPER|iNTERNAL|RERIP|REAL)\." )" == "" ] ; then if [ "$( echo $file | /opt/bin/grep "720p" )" != "" ] ; then REN="$REN -e ""s/\(.*S[0-9]\+\(E[0-9]\+\)\+\)\+.*\(720p.*\)/\1.\3/""" fi if [ "$( echo $file | /opt/bin/grep "1080p" )" != "" ] ; then REN="$REN -e ""s/\(.*S[0-9]\+\(E[0-9]\+\)\+\)\+.*\(1080p.*\)/\1.\3/""" fi fi NEW="$( echo $OLD | /opt/bin/sed $REN )" if [ ! -z "$NEW" -a "$NEW" != "$OLD" ] ; then echo "Enforcing naming scheme for $file" mv "$OLD" "$NEW" fi done [ "$OPTS" = "--force" ] && RESCAN_ALL=1 || RESCAN_ALL=0 IFS=" " if [ $RESCAN_ALL -eq 1 ] ; then FILES="`/opt/bin/grep -rl 'episodedetails' */*/*.nfo 2>/dev/null`" else # Get a list of all NFO files having incorrect information FILES="`/opt/bin/egrep -rli '(\(Guest Star\)|\(Writer\))' */*/*.nfo 2>/dev/null`" fi for episode in $FILES; do # First convert the nfo-file to use linux line-breaks. /opt/bin/sed -i 's/^M$//' $episode if [ "$( /opt/bin/grep '<director>.*</director>' $episode )" == "" ] ; then DIRECTOR_MISSING="$DIRECTOR_MISSING $episode" fi if [ "$( /opt/bin/grep '<credits>.*</credits>' $episode )" == "" ]; then CREDITS_MISSING="$CREDITS_MISSING $episode" fi if [ "$( /opt/bin/grep '<credits>.*\(Writer\).*</credits>' $episode )" == "" ]; then WRITER_MISSING="$WRITER_MISSING $episode" fi if [ "$( /opt/bin/grep '<credits>.*\&amp;.*</credits>' $episode )" != "" ]; then CREDITS_JUNK="$CREDITS_JUNK $episode" else # see if the file has new-style (multi-line) or old-style (single-line) credits. if [ "$( /opt/bin/grep '<credits>' $episode | wc -l )" -gt 1 ] ; then echo "Updating episode information in $episode (new-style)" mv $episode $episode.old /opt/bin/grep -v "(Guest Star)</credits>" $episode.old | /opt/bin/sed \ -e "s, (Writer),,g" -e -e "s,|, / ,g" \ -e "s, , ,g" -e 's/^[ \t]*//' | \ tee $episode &>/dev/null else # Mangle the list, so we can work with it old_credits="$( /opt/bin/grep "<credits>" $episode | /opt/bin/sed -n \ -e 's/.*<credits>\(.*\)<\/credits>.*/\1/p' )" # Fixup the credits line new_credits="$( echo $old_credits | tr '/' '\n' | /opt/bin/grep -v "Guest Star" | \ tr '\n' '/' | /opt/bin/sed -e "s, (Writer),,g" \ -e "s,|, / ,g" -e "s, , ,g" | /opt/bin/sed -e 's/^[ \t]*//' \ -e "s/\/*$//" )" shopt -q -s extglob echo "Updating episode information in $episode (old-style)" if [ -n "$new_credits" ] ; then /opt/bin/sed -i "s|${old_credits##+([[:space:]])}|$new_credits|g" $episode fi shopt -q -u extglob fi fi done IFS=" " if [ -n "$DIRECTOR_MISSING" ] ; then echo "The following episodes are missing a director:" for episode in $DIRECTOR_MISSING; do echo " $episode" done echo fi if [ -n "$CREDITS_JUNK" ] ; then echo "The following episodes credits' contain junk and should be fixed at thetvdb.com:" for episode in $CREDITS_JUNK; do echo " $episode" done echo fi if [ -n "$CREDITS_MISSING" ] ; then echo "The following episodes are missing credits:" for episode in $CREDITS_MISSING; do echo " $episode" done echo fi if [ -n "$WRITER_MISSING" ] ; then echo "The following episodes are missing a writer:" for episode in $WRITER_MISSING; do echo " $episode" done fi /opt/bin/findutils-find . -name "*.old" -exec rm {} \; Bear in mind, this script is using ipkg/optware executables, mainly because the provided BusyBox ones are lacking some features.

April 6, 2015 · 6 min · 1130 words · christian

PowerCLI: Delete all snapshots by name

I have the issue that we use a cloud automation software, which for whatever reason failed to delete the hypervisor snapshots. Now I was looking into a quick way to delete all those 520 snapshots with PowerCLI, and I found something pretty quick. Based on that, I came up with my own quick PowerCLI one-liner, that’ll list all VMs and their snapshots: 1 Get-VM | Get-Snapshot | Where { $_.Name -like "201502*" } | Format-Table -Property VM, Name, Created, Description, SizeMB -AutoSize Now, I could use another one-liner to delete all snapshots, that’ll look like this: ...

February 23, 2015 · 2 min · 231 words · christian

Migrating from XenServer to ESXi

For the past two months we’ve been trying to migrate a bunch (90 or so) VMs from XenServer to ESXi … However for some reason on some of them, the Converter Service would crash. VMware Converter crashing due to rsintcor32.dll Up till Monday, I had no idea why. I decided to look into the error once again, and this time decided just to Google the failing module… And guess what ? Out came this Citrix forum post regarding the failing module. So, after knowing that rsintcor32.dll belongs to the Citrix System Monitoring Agent service (well, I could have guessed that from the DLLs path 😛) I decided to simply stop the service. ...

February 19, 2015 · 1 min · 127 words · christian

Tiny Tiny RSS init-script for multiple instances on Debian Wheezy

Well, I have a bunch of Tiny Tiny RSS instances running on my webhost, and I wanted a init-script that starts the update-daemons for all instances. Now, there’s already a bunch of init scripts for Debian around ( 1, 2) however none of them were to my liking or did what I wanted it to do. So I ended up (yeah, I know again) rewriting them. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 #!/bin/sh ### BEGIN INIT INFO # Provides: ttrss # Required-Start: $local_fs $remote_fs networking # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Tiny Tiny RSS update daemon # Description: Update the Tiny Tiny RSS subscribed syndication feeds. ### END INIT INFO set -e PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Tiny Tiny RSS update daemon" NAME=$(command basename "${0}") DISABLED=1 FORKING=0 # Read configuration variable file if it is present [ -r "/etc/default/${NAME}" ] && . "/etc/default/${NAME}" DAEMON_SCRIPT="update.php --daemon" if [ $FORKING -ne 0 ] ; then DAEMON_SCRIPT="update_daemon2.php" fi DAEMON=/usr/bin/php # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 [ -d "${TTRSS_PATH}" ] || exit 0 # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions if [ "$DISABLED" != "0" -a "$1" != "stop" ]; then log_warning_msg "Not starting $DESC - edit /etc/default/tt-rss and change DISABLED to be 0."; exit 0; fi # Function that starts the daemon/service do_start() { for dir in ${TTRSS_PATH}/*; do INSTANCE_NAME=${dir##*/} start-stop-daemon --start --make-pidfile --background --quiet --chuid "${TTRSS_USERID}" --group "${TTRSS_GROUPID}" --chdir "${dir}" --pidfile "${TTRSS_PIDDIR}/ttrss-${INSTANCE_NAME}.pid" --exec "${DAEMON}" --test >/dev/null || return 1 start-stop-daemon --start --make-pidfile --background --quiet --chuid "${TTRSS_USERID}" --group "${TTRSS_GROUPID}" --chdir "${dir}" --pidfile "${TTRSS_PIDDIR}/ttrss-${INSTANCE_NAME}.pid" --exec "${DAEMON}" -- ${dir}/${DAEMON_SCRIPT} --log /var/log/ttrss/${INSTANCE_NAME}.log || return 2 done } # Function that stops the daemon/service do_stop() { for dir in ${TTRSS_PATH}/*; do INSTANCE_NAME=${dir##*/} start-stop-daemon --stop --make-pidfile --quiet --retry=TERM/1/KILL/5 --pidfile "${TTRSS_PIDDIR}/ttrss-${INSTANCE_NAME}.pid" RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 start-stop-daemon --stop --quiet --oknodo --retry=0/1/KILL/5 --exec ${DAEMON} [ "$?" = 2 ] && return 2 rm -f "${TTRSS_PIDDIR}/ttrss-${INSTANCE_NAME}.pid" return $RETVAL done } case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; restart|force-reload) # If the "reload" option is implemented then remove the # 'force-reload' alias log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: ${NAME} {start|stop|restart|force-reload}" >&2 exit 3 ;; esac : 1 2 3 4 5 6 7 8 9 10 11 12 # Set DISABLED to 1 to prevent the daemon from starting. DISABLED=0 TTRSS_USERID="www-data" TTRSS_GROUPID="www-data" TTRSS_PIDDIR="/var/run" TTRSS_PATH="/var/www/rss.heimdaheim.de/www" # Allow the update_daemon script to use a forking daemon instead of a # single-threaded instance. # This option is only available for TinyTinyRSS 1.2.20 and above. FORKING=0

February 9, 2015 · 4 min · 651 words · christian

Quick-Add a bunch of Virtual Machine Port-Groups from CSV

Well, I’m currently migrating between different cluster layouts, and I had to create the new PortGroups on the old hosts, in order for me to switch between old and new hosts. 1 2 3 4 5 6 7 $vmhosts = Get-Cluster "UCSCL01-02" | Get-VMHost foreach ($vmhost in $vmhosts) { import-csv -Delimiter ";" .\pg.csv | foreach { $vmhost | Get-VirtualSwitch -Name "vSwitch3" | New-VirtualPortGroup ` -Name $_.portgroup -VLanId $_.vlanid } } And the corresponding CSV would look like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 portgroup;vlanid 1700_routers;1700 1701_routers;1701 1702_routers;1702 1703_routers;1703 1704_routers;1704 1705_routers;1705 1706_routers;1706 1707_routers;1707 1708_routers;1708 1709_routers;1709 1710_routers;1710 1711_routers;1711 1712_routers;1712 1713_routers;1713 1714_routers;1714 1715_routers;1715 1716_routers;1716 1717_routers;1717 1718_routers;1718 1719_routers;1719 2000_virtual-machines;2000 2001_virtual-machines;2001 2002_virtual-machines;2002 2003_virtual-machines;2003 2004_virtual-machines;2004 2005_virtual-machines;2005 2006_virtual-machines;2006 2007_virtual-machines;2007 2008_virtual-machines;2008 2009_virtual-machines;2009 2010_virtual-machines;2010 2011_virtual-machines;2011 2012_virtual-machines;2012 2013_virtual-machines;2013 2014_virtual-machines;2014 2015_virtual-machines;2015 2016_virtual-machines;2016 2017_virtual-machines;2017 2018_virtual-machines;2018 2019_virtual-machines;2019

January 3, 2015 · 1 min · 160 words · christian

ViMbAdmin and mod_rewrite

Well, I use ViMbAdmin for the mail box administration of my users (and aliases) on heimdaheim.de. After I while (well, over half a year I guess), I decided to look at it again. However it didn’t work. Well this was a multi-part problem. ViMbAdmin has been updated to require PHP composer (which populates the vendor/ folder) the application.ini was outdated After I fixed all that, ViMbAdmin was working again. However I decided to replace my mod_rewrite stuff (I had in my apache config from the previous version) with the one from the Documentation and that actually made things worse. So I ended up redigging into mod_rewrite (again sigh) and rewrite the Rewrite Rules… This time I’m documenting it. ...

December 2, 2014 · 1 min · 157 words · christian

Adjust album list display in foobar2000

Well, as I said earlier I’ve been playing around with my Sonos (and in that regard cleaning up my music library). Now, I started setting up my foobar2000 to ignore articles (The, A) when moving/copying file to my music library. For example, previously the structure would have looked like this: 1 albums\T\The Beatles - 1963-03-22 - Please Please Me Now, after implementing the file operations adjustments (I’ll post them later), the structure looks like this: ...

November 13, 2014 · 1 min · 202 words · christian

Download a (legal) Windows 8-1 Media Refresh ISO

Well, Microsoft finally had an insight into the user complaints about not being able to download a (legal) Media Refresh ISO for people with preinstalled Windows 8(.1). Now, you just have to download the Media Creation Tool from http://windows.microsoft.com/en-us/windows-8/create-reset-refresh-media. It’s portable, just execute the EXE and it’ll download you the selected Windows 8(.1) ISO you selected. Additionally, it finally accepts the Product Keys from Windows 8, which is a big step.

November 13, 2014 · 1 min · 71 words · christian

Display MusicBrainz info in foobar2000

I’ve been cleaning up my music library the past few days (well, I bought a Sonos 😀), so here’s how you display for example the tagging field MUSICBRAINZ ALBUM TYPE in foobar2000’s default metadata view. Goto preferences (Ctrl+P or File->Preferences) Navigate to Advanced Extend the Display node, extend Properties Dialoge node There you’ll find the option for Standard fields Change it to the following: 1 Artist Name=ARTIST;Track Title=TITLE;Album Title=ALBUM;Date=DATE;Genre=GENRE;Composer=COMPOSER;Performer=PERFORMER;Album Artist=ALBUM ARTIST;Track Number=TRACKNUMBER;Total Tracks=TOTALTRACKS;Disc Number=DISCNUMBER;Total Discs=TOTALDISCS;Comment=COMMENT;Album Type=MUSICBRAINZ ALBUM TYPE After changing the Standard fields option, the metadata view will look like this: ...

November 13, 2014 · 1 min · 91 words · christian