<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Knowledge Base (Posts about symlink)</title><link>https://bgstack15.ddns.net/blog/</link><description></description><atom:link href="https://bgstack15.ddns.net/blog/categories/symlink.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2024 &lt;a href="mailto:bgstack15@gmail.com"&gt;bgstack15&lt;/a&gt; 
&lt;a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/"&gt;
&lt;img alt="Creative Commons License BY-SA"
style="border-width:0; margin-bottom:12px;"
src="https://bgstack15.ddns.net/.images/l_by-sa_4.0_88x31.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Sun, 10 Mar 2024 13:33:31 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>jellyfin show manager</title><link>https://bgstack15.ddns.net/blog/posts/2024/03/10/jellyfin-show-manager/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I'm back with an overengineered solution for myself. I have a complete show, but I want to have Jellyfin show only up to 2 new episodes at a time. I'll set a cron job to check and add new episodes from the real location as necessary.&lt;/p&gt;
&lt;p&gt;So, the overcomplicated script:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/show-manager.sh.html"&gt;files/2024/listings/show-manager.sh&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/show-manager.sh"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# File: show-manager.sh&lt;/span&gt;
&lt;span class="c1"&gt;# Location: /mnt/public/Support/Programs/jellyfin/scripts/&lt;/span&gt;
&lt;span class="c1"&gt;# Author: bgstack15&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2024-02-18-1 17:24&lt;/span&gt;
&lt;span class="c1"&gt;# SPDX-License-Identifier: GPL-3.0-only&lt;/span&gt;
&lt;span class="c1"&gt;# Title: Slowly add new episodes of a completed show to jellyfin&lt;/span&gt;
&lt;span class="c1"&gt;# Purpose: Check jellyfin for if the last season of a given show is greater than (x-2)/x episodes, and if so, then add that many new episodes.&lt;/span&gt;
&lt;span class="c1"&gt;# History:&lt;/span&gt;
&lt;span class="c1"&gt;# Usage:&lt;/span&gt;
&lt;span class="c1"&gt;#    . ./jellystack-autocomplete.bash ; manage_show stsnw&lt;/span&gt;
&lt;span class="c1"&gt;# Improve:&lt;/span&gt;
&lt;span class="c1"&gt;#    hook in to jellyfin deeper, by checking file paths of the episodes where watched=True, to know which episodes to skip trying to add&lt;/span&gt;
&lt;span class="c1"&gt;#    learn how to completely clear the "watched" information about the show in jellyfin.&lt;/span&gt;
&lt;span class="c1"&gt;# Documentation:&lt;/span&gt;
&lt;span class="c1"&gt;#    Assumptions:&lt;/span&gt;
&lt;span class="c1"&gt;#       1. media files are sorted in "Season 01/" type directories.&lt;/span&gt;
&lt;span class="c1"&gt;#       2. Media files are named "*s01e07 *" style which will be sorted alphabetically in episode number order.&lt;/span&gt;
&lt;span class="c1"&gt;#       3. watched episodes are in exact order!&lt;/span&gt;
&lt;span class="c1"&gt;#       4. input files are all mkv (this is to simplify filtering out non-episode files like images; it could be made more complex as needed)&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    jellystack_lib with watched_episodes_for_show()&lt;/span&gt;

&lt;span class="c1"&gt;# flow:&lt;/span&gt;
&lt;span class="c1"&gt;# get episodes-watched for last season of show (value is, e.g., "8/10"&lt;/span&gt;


&lt;span class="c1"&gt;# depends on content being in "Season 01/" directories.&lt;/span&gt;
get_episodes_watched_count&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# input env vars: library, show, DEBUG&lt;/span&gt;
   &lt;span class="c1"&gt;# output: prints watched= and total= numbers&lt;/span&gt;
   &lt;span class="c1"&gt;# usage: $( library="TV" show="Star Trek: Strange New Worlds" get_episodes_watched_count )&lt;/span&gt;
   &lt;span class="nv"&gt;_pyverbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;False
   &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;_pyverbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True
   &lt;span class="nb"&gt;cd&lt;/span&gt; /mnt/public/Support/Programs/jellyfin/scripts
   . ~/.config/jellystack.viewing.user
   &lt;span class="o"&gt;{&lt;/span&gt;
      python3 &lt;span class="s"&gt;&amp;lt;&amp;lt;-EOF&lt;/span&gt;
&lt;span class="s"&gt;import jellystack_lib&lt;/span&gt;
&lt;span class="s"&gt;a = jellystack_lib.get_authenticated_client(url="${server}",username="${username}",password="${password}")&lt;/span&gt;
&lt;span class="s"&gt;b = jellystack_lib.watched_episodes_for_show(a,"${library}","${show}","sum",${_pyverbose})&lt;/span&gt;
&lt;span class="s"&gt;c = b.split("/")&lt;/span&gt;
&lt;span class="s"&gt;print(f"watched={c[0]}")&lt;/span&gt;
&lt;span class="s"&gt;print(f"total={c[1]}")&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

symlink_file&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# input vars: infile SOURCE_DIR LINK_DIR LINK_PREFIX VERBOSE APPLY&lt;/span&gt;
   &lt;span class="c1"&gt;# reference: printf '%s\n' *s01e0* | while read line ; do ln -sf "../../../off.movies/Star Trek - Strange New Worlds (2021/Season 01/${line}" "/mnt/public/Video/TV/Star Trek - Strange New Worlds (2021/Season 01/" ; done&lt;/span&gt;
   &lt;span class="c1"&gt;# We now calculate season number based on file name&lt;/span&gt;
   &lt;span class="c1"&gt;#season_num_str="$( \printf '%02d' "${season_num}" )"&lt;/span&gt;
   &lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; basename &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;season_num_str&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="se"&gt;\p&lt;/span&gt;rintf &lt;span class="s1"&gt;'%02d'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -oE &lt;span class="s1"&gt;'\&amp;lt;s[0-9]+e[0-9]+'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk -F&lt;span class="s1"&gt;'e'&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr -dc &lt;span class="s1"&gt;'0-9'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERBOSE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; ln -s &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINK_PREFIX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Season &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;season_num_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Season &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;season_num_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APPLY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ln -s &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINK_PREFIX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Season &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;season_num_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LINK_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/Season &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;season_num_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

list_sorted_episode_files&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# input env vars: SOURCE_DIR&lt;/span&gt;
   &lt;span class="c1"&gt;# if changing from %P, probably do a cd in a sub-shell.&lt;/span&gt;
   find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SOURCE_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -name &lt;span class="s1"&gt;'*mkv'&lt;/span&gt; -iregex &lt;span class="s1"&gt;'.*\&amp;lt;s[0-9]+e[0-9]+\&amp;gt;.*'&lt;/span&gt; -printf &lt;span class="s1"&gt;'%P\n'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sort -n
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Logic flow:&lt;/span&gt;
&lt;span class="c1"&gt;# diff=total-watched&lt;/span&gt;
&lt;span class="c1"&gt;# if diff &amp;lt; 2,&lt;/span&gt;
&lt;span class="c1"&gt;#    find the smallest-number episode files and add them in.&lt;/span&gt;
manage_show&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# input vars: MAX_NEW_EPISODES SOURCE_DIR VERBOSE LIBRARY SHOW&lt;/span&gt;
   &lt;span class="c1"&gt;# You may also run: manage_show "TV/Star Trek: Strange New Worlds"&lt;/span&gt;
   &lt;span class="nv"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -f &lt;span class="s2"&gt;"/mnt/public/Support/Programs/jellyfin/scripts/input/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;conf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.conf"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; . &lt;span class="s2"&gt;"/mnt/public/Support/Programs/jellyfin/scripts/input/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;conf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.conf"&lt;/span&gt;
   &lt;span class="c1"&gt;# Not necessary with the conf file method&lt;/span&gt;
   &lt;span class="c1"&gt;#test -z "${SHOW}" &amp;amp;&amp;amp; test -z "${LIBRARY}" &amp;amp;&amp;amp; {&lt;/span&gt;
   &lt;span class="c1"&gt;#   LIBRARY="$( echo "${1}" | awk -F'/' '{print $1}' )"&lt;/span&gt;
   &lt;span class="c1"&gt;#   SHOW="$( echo "${1}" | awk -F'/' '{print $2}' )"&lt;/span&gt;
   &lt;span class="c1"&gt;#}&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_NEW_EPISODES&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;MAX_NEW_EPISODES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
   &lt;span class="c1"&gt;# this next function sets vars: watched, total&lt;/span&gt;
   &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nv"&gt;library&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LIBRARY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;show&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SHOW&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; get_episodes_watched_count &lt;span class="k"&gt;)&lt;/span&gt;
   &lt;span class="c1"&gt;# hardcode these to test max_new_episodes&lt;/span&gt;
   &lt;span class="c1"&gt;#watched=6 total=8&lt;/span&gt;
   &lt;span class="nv"&gt;diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;total-watched&lt;span class="k"&gt;))&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERBOSE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Got watched=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;watched&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; total=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; diff=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;diff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;diff&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; -lt &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_NEW_EPISODES&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nv"&gt;need&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;MAX_NEW_EPISODES-diff&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Must prepare next &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;need&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; episodes."&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="nv"&gt;w1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;watched+1&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;watched+need&lt;span class="k"&gt;))&lt;/span&gt;
      list_sorted_episode_files &lt;span class="p"&gt;|&lt;/span&gt; sed -n -r -e &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;w1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;p"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; infile &lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;do&lt;/span&gt;
         &lt;span class="c1"&gt;# VERBOSE and APPLY are used in this function:&lt;/span&gt;
         &lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; symlink_file
      &lt;span class="k"&gt;done&lt;/span&gt;
   &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Before the config file redesign, use one of these:&lt;/span&gt;
&lt;span class="c1"&gt;# These will still get "/Season 01" prepended to the file basename:&lt;/span&gt;
&lt;span class="c1"&gt;# SOURCE_DIR="/mnt/public/Video/off.movies/Star Trek - Strange New Worlds (2021)" LINK_DIR="/mnt/public/Video/TV/Star Trek - Strange New Worlds (2021)" LINK_PREFIX="../../../off.movies/Star Trek - Strange New Worlds (2021)" LIBRARY="TV" SHOW="Star Trek - Strange New Worlds (2021)" DIR="${SHOW}" manage_show&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So I'm pretty sure this uses yet a new password file, this time as a shell snippet with export statements of the interesting variables, &lt;code&gt;~/.config/jellystack.viewing.user&lt;/code&gt;. (I don't use the admin user for actually watching, what am I, ridiculous?!)&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"KEEPASS"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"jellyfin"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"http://vm4:8096"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then with this autocomplete:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/jellystack-autocomplete.bash.html"&gt;files/2024/listings/jellystack-autocomplete.bash&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/jellystack-autocomplete.bash"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c1"&gt;# trimmed for blog&lt;/span&gt;
_show_manager_confs&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# reference: vm4:/etc/bash_completion.d/docker-nfs-check&lt;/span&gt;
   &lt;span class="nb"&gt;local&lt;/span&gt; cur prev words cword&lt;span class="p"&gt;;&lt;/span&gt;
   _init_completion &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
   &lt;span class="nv"&gt;_tmpfile1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; mktemp &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="c1"&gt;# populate list&lt;/span&gt;
   find /mnt/public/Support/Programs/jellyfin/scripts/input -mindepth &lt;span class="m"&gt;1&lt;/span&gt; -maxdepth &lt;span class="m"&gt;1&lt;/span&gt; ! -type d -name &lt;span class="s1"&gt;'*.conf'&lt;/span&gt; -printf &lt;span class="s1"&gt;'%P\n'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;'s/\.conf$//;'&lt;/span&gt; &amp;gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_tmpfile1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;COMPREPLY&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;compgen&lt;/span&gt; -W &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; cat &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_tmpfile1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -- &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$cur&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s2"&gt;"/^&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;prev&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/d;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
   &lt;span class="nb"&gt;command&lt;/span&gt; rm -rf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;_tmpfile1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;NOTHINGTODEL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;/dev/null &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nb"&gt;complete&lt;/span&gt; -F _show_manager_confs manage-show
. /mnt/public/Support/Programs/jellyfin/scripts/show-manager.sh
&lt;span class="nb"&gt;alias&lt;/span&gt; manage-show&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"manage_show"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And any number of files in that &lt;code&gt;input/&lt;/code&gt; directory:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/strangenewworlds.conf.example.html"&gt;files/2024/listings/strangenewworlds.conf.example&lt;/a&gt;  &lt;a href="https://bgstack15.ddns.net/blog/files/2024/listings/strangenewworlds.conf.example"&gt;(Source)&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Where all the episode mkv files are&lt;/span&gt;
&lt;span class="nv"&gt;SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/mnt/public/Video/off.movies/Star Trek - Strange New Worlds (2021)"&lt;/span&gt;
&lt;span class="c1"&gt;# Where they should be placed for Jellyfin to pick them up&lt;/span&gt;
&lt;span class="nv"&gt;LINK_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/mnt/public/Video/TV/Star Trek - Strange New Worlds (2021)"&lt;/span&gt;
&lt;span class="c1"&gt;# Symlink prefix, so probably the relative path from LINK_DIR to SOURCE_DIR&lt;/span&gt;
&lt;span class="nv"&gt;LINK_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"../../../off.movies/Star Trek - Strange New Worlds (2021)"&lt;/span&gt;
&lt;span class="c1"&gt;# Jellyfin library name&lt;/span&gt;
&lt;span class="nv"&gt;LIBRARY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"TV"&lt;/span&gt;
&lt;span class="c1"&gt;# Jellyfin show name&lt;/span&gt;
&lt;span class="nv"&gt;SHOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Star Trek: Strange New Worlds"&lt;/span&gt;
&lt;span class="c1"&gt;# Show directory name. Not necessarily the same as SHOW.&lt;/span&gt;
&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Star Trek - Strange New Worlds (2021)"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So if I've watched 6/7 episodes, and &lt;code&gt;MAX_NEW_EPISODES=2&lt;/code&gt;, then it should symlink in one new episode.&lt;/p&gt;
&lt;p&gt;This process counts incorrectly sometimes (because I originally had all the episode files available to it and the counting got messed up), so I just keep increasing &lt;code&gt;MAX_NEW_EPISODES&lt;/code&gt; until it puts the correct number of new episodes in the path for Jellyfin.&lt;/p&gt;
&lt;p&gt;So I just run:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;. &lt;span class="nv"&gt;jellystack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;autocomplete&lt;/span&gt;.&lt;span class="nv"&gt;bash&lt;/span&gt;
&lt;span class="nv"&gt;VERBOSE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nv"&gt;MAX_NEW_EPISODES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="nv"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And list the show confs, and pick one, and then run it. Once it looks good, I re-run with &lt;code&gt;APPLY=1&lt;/code&gt;.&lt;/p&gt;</description><category>autocomplete</category><category>files</category><category>jellyfin</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2024/03/10/jellyfin-show-manager/</guid><pubDate>Sun, 10 Mar 2024 13:24:39 GMT</pubDate></item><item><title>Convert .lnk shortcut to symlink</title><link>https://bgstack15.ddns.net/blog/posts/2021/02/18/convert-lnk-shortcut-to-symlink/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;Related to my &lt;a href="https://bgstack15.ddns.net/blog/posts/2021/02/02/web-gallery-solution/"&gt;Web gallery
solution&lt;/a&gt;
and &lt;a href="https://bgstack15.ddns.net/blog/posts/2021/02/06/symlink-forest-generator/"&gt;Symlink forest
generator&lt;/a&gt;, I wanted a way to convert Windows-style shortcuts (.lnk files) to
symlinks. Apparently I am the first person to publish this research on the
Internet. Nobody else in the world has discussed performing this operation.
It's probably foolhardy, but it was technically interesting. I wrote the
&lt;a href="https://gitlab.com/bgstack15/s2s"&gt;shortcut2symlink&lt;/a&gt; python library and cli
tool.&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;A Windows client is used to maintain a website/ subdirectory of files that
will be processed using the &lt;a href="https://gitlab.com/bgstack15/gallery"&gt;gallery&lt;/a&gt;
project. To facilitate the process of preparing files for this website/
subdirectory, particularly over a wireless network connection, users have been
instructed to just make Windows-style shortcuts (using CTRL+SHIFT dragging) in
the website subdirectory in whatever layout desired. This project includes
components that will scan the designated directory for .lnk files anywhere
underneath, and interpret their targets, and generate symlinks in place of the
.lnk files. Unfortunately my scanner (inotify) is slightly flaky, and
sometimes I still need to manually run the s2s.py command directly. The point
of using symlinks in this case is to reduce the disk usage and number of
duplicate files and directories. To SMB users on the Windows client, the
symlink files will look like copies, but that is acceptable because the main
focus is the gallery generation for the web server.&lt;/p&gt;
&lt;h3&gt;Reason for existence&lt;/h3&gt;
&lt;p&gt;Reduce disk space by removing duplicate files, while still having a whole
directory structure readable by the gallery solution for generating static
site pages, and while making it easy for wireless network users to "manage"
links to files at least initially.&lt;/p&gt;
&lt;h3&gt;Example usage&lt;/h3&gt;
&lt;p&gt;For the inotify script:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/mnt/public/Support/Programs/shortcuts/s2s-inotify.sh /mnt/public/Images/username1-photos/website
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And for manually running:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/mnt/public/Support/Programs/shortcuts/s2s.py --indir /mnt/public/Images/username1-photos/website --apply --debug 8 --delete
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;References&lt;/h2&gt;
&lt;h3&gt;Weblinks&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc"&gt;.lnk format
reference&lt;/a&gt;&lt;/p&gt;</description><category>original</category><category>python</category><category>shortcut</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2021/02/18/convert-lnk-shortcut-to-symlink/</guid><pubDate>Thu, 18 Feb 2021 13:56:41 GMT</pubDate></item><item><title>Symlink forest generator</title><link>https://bgstack15.ddns.net/blog/posts/2021/02/06/symlink-forest-generator/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;As part of my &lt;a href="https://bgstack15.ddns.net/blog/posts/2021/02/02/web-gallery-solution/"&gt;Web gallery
solution&lt;/a&gt;, I
wrote some logic that creates a YYYY/MM directory creator that places symlinks
to my original files within the new directory structure. The links are added
to the relevant directory based on exif metadata if possible, and file
timestamp as a last resort. Check out the source files at my
&lt;a href="https://gitlab.com/bgstack15/gallery"&gt;gitlab&lt;/a&gt; space:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/bgstack15/gallery/-/blob/master/generate.py"&gt;generate.py&lt;/a&gt; front end for cli&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/bgstack15/gallery/-/blob/master/genlib.py"&gt;genlib.py&lt;/a&gt; library&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is my main sample invocation. I used this a lot while testing.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bgstack15&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Backups&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Images&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2018&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mnt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gallery&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;my2018&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="bp"&gt;x&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;October&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;nr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The help text is generated with ArgumentParser.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ ./generate.py --helpusage: generate.py &lt;span class="o"&gt;[&lt;/span&gt;-h&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-d &lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,1,2,3,4,5,6,7,8,9,10&lt;span class="o"&gt;}]]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-v&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-n &lt;span class="p"&gt;|&lt;/span&gt; -a&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-z &lt;span class="p"&gt;|&lt;/span&gt; --nz&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-c &lt;span class="p"&gt;|&lt;/span&gt; -s &lt;span class="p"&gt;|&lt;/span&gt; -m&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;-r &lt;span class="p"&gt;|&lt;/span&gt; --nr&lt;span class="o"&gt;]&lt;/span&gt; -i
                   INDIR -o OUTDIR &lt;span class="o"&gt;[&lt;/span&gt;-x EXCLUDE&lt;span class="o"&gt;]&lt;/span&gt;

Make symlink forest &lt;span class="k"&gt;for&lt;/span&gt; images

optional arguments:
  -h, --help            show this &lt;span class="nb"&gt;help&lt;/span&gt; message and &lt;span class="nb"&gt;exit&lt;/span&gt;
  -d &lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,1,2,3,4,5,6,7,8,9,10&lt;span class="o"&gt;}]&lt;/span&gt;, --debug &lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,1,2,3,4,5,6,7,8,9,10&lt;span class="o"&gt;}]&lt;/span&gt;
                        Set debug level
  -v, --version         show program&lt;span class="err"&gt;'&lt;/span&gt;s version number and &lt;span class="nb"&gt;exit&lt;/span&gt;
  -n, --dryrun          Make no changes &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
  -a, --apply           Actually make changes
  -z, -0, --zeropad     Zero pad month directories &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
  --nz, --nozeropad, --no-zeropad
                        Do not zero pad
  -c, --copy            Copy files instead of symlinks. Not recommended.
  -s, --symlink         Make symlinks &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
  -m, --move            Move files. Not recommended.
  -r, --relative        Make relative symlinks &lt;span class="k"&gt;if&lt;/span&gt; possible.
  --nr, --norelative, --no-relative
                        Make absolute symlinks &lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
  -i INDIR, --indir INDIR
  -o OUTDIR, --outdir OUTDIR
  -x EXCLUDE, --exclude EXCLUDE
                        Exclude pathname matches. Can be used multiple times.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For posterity and in case my gitlab ever dies, here are their contents at the
time of this writing.&lt;/p&gt;
&lt;h4&gt;generate.py&lt;/h4&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;
&lt;span class="normal"&gt;104&lt;/span&gt;
&lt;span class="normal"&gt;105&lt;/span&gt;
&lt;span class="normal"&gt;106&lt;/span&gt;
&lt;span class="normal"&gt;107&lt;/span&gt;
&lt;span class="normal"&gt;108&lt;/span&gt;
&lt;span class="normal"&gt;109&lt;/span&gt;
&lt;span class="normal"&gt;110&lt;/span&gt;
&lt;span class="normal"&gt;111&lt;/span&gt;
&lt;span class="normal"&gt;112&lt;/span&gt;
&lt;span class="normal"&gt;113&lt;/span&gt;
&lt;span class="normal"&gt;114&lt;/span&gt;
&lt;span class="normal"&gt;115&lt;/span&gt;
&lt;span class="normal"&gt;116&lt;/span&gt;
&lt;span class="normal"&gt;117&lt;/span&gt;
&lt;span class="normal"&gt;118&lt;/span&gt;
&lt;span class="normal"&gt;119&lt;/span&gt;
&lt;span class="normal"&gt;120&lt;/span&gt;
&lt;span class="normal"&gt;121&lt;/span&gt;
&lt;span class="normal"&gt;122&lt;/span&gt;
&lt;span class="normal"&gt;123&lt;/span&gt;
&lt;span class="normal"&gt;124&lt;/span&gt;
&lt;span class="normal"&gt;125&lt;/span&gt;
&lt;span class="normal"&gt;126&lt;/span&gt;
&lt;span class="normal"&gt;127&lt;/span&gt;
&lt;span class="normal"&gt;128&lt;/span&gt;
&lt;span class="normal"&gt;129&lt;/span&gt;
&lt;span class="normal"&gt;130&lt;/span&gt;
&lt;span class="normal"&gt;131&lt;/span&gt;
&lt;span class="normal"&gt;132&lt;/span&gt;
&lt;span class="normal"&gt;133&lt;/span&gt;
&lt;span class="normal"&gt;134&lt;/span&gt;
&lt;span class="normal"&gt;135&lt;/span&gt;
&lt;span class="normal"&gt;136&lt;/span&gt;
&lt;span class="normal"&gt;137&lt;/span&gt;
&lt;span class="normal"&gt;138&lt;/span&gt;
&lt;span class="normal"&gt;139&lt;/span&gt;
&lt;span class="normal"&gt;140&lt;/span&gt;
&lt;span class="normal"&gt;141&lt;/span&gt;
&lt;span class="normal"&gt;142&lt;/span&gt;
&lt;span class="normal"&gt;143&lt;/span&gt;
&lt;span class="normal"&gt;144&lt;/span&gt;
&lt;span class="normal"&gt;145&lt;/span&gt;
&lt;span class="normal"&gt;146&lt;/span&gt;
&lt;span class="normal"&gt;147&lt;/span&gt;
&lt;span class="normal"&gt;148&lt;/span&gt;
&lt;span class="normal"&gt;149&lt;/span&gt;
&lt;span class="normal"&gt;150&lt;/span&gt;
&lt;span class="normal"&gt;151&lt;/span&gt;
&lt;span class="normal"&gt;152&lt;/span&gt;
&lt;span class="normal"&gt;153&lt;/span&gt;
&lt;span class="normal"&gt;154&lt;/span&gt;
&lt;span class="normal"&gt;155&lt;/span&gt;
&lt;span class="normal"&gt;156&lt;/span&gt;
&lt;span class="normal"&gt;157&lt;/span&gt;
&lt;span class="normal"&gt;158&lt;/span&gt;
&lt;span class="normal"&gt;159&lt;/span&gt;
&lt;span class="normal"&gt;160&lt;/span&gt;
&lt;span class="normal"&gt;161&lt;/span&gt;
&lt;span class="normal"&gt;162&lt;/span&gt;
&lt;span class="normal"&gt;163&lt;/span&gt;
&lt;span class="normal"&gt;164&lt;/span&gt;
&lt;span class="normal"&gt;165&lt;/span&gt;
&lt;span class="normal"&gt;166&lt;/span&gt;
&lt;span class="normal"&gt;167&lt;/span&gt;
&lt;span class="normal"&gt;168&lt;/span&gt;
&lt;span class="normal"&gt;169&lt;/span&gt;
&lt;span class="normal"&gt;170&lt;/span&gt;
&lt;span class="normal"&gt;171&lt;/span&gt;
&lt;span class="normal"&gt;172&lt;/span&gt;
&lt;span class="normal"&gt;173&lt;/span&gt;
&lt;span class="normal"&gt;174&lt;/span&gt;
&lt;span class="normal"&gt;175&lt;/span&gt;
&lt;span class="normal"&gt;176&lt;/span&gt;
&lt;span class="normal"&gt;177&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2021-01-29 15:35&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    devuan-req: python3-exifread&lt;/span&gt;
&lt;span class="c1"&gt;# Reference:&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/1192978/python-get-relative-path-of-all-files-and-subfolders-in-a-directory&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/3207219/how-do-i-list-all-files-of-a-directory&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;exifread&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;process_file&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symlink&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;shutil&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;copy2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# Functions&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;relative&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Listing all files underneath &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"While excluding path matches:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dirnames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
         &lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
         &lt;span class="n"&gt;use_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# simple match, no regex&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
               &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
               &lt;span class="n"&gt;use_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
               &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="c1"&gt;# short-circuit&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;relative&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"ignored per &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;use_pattern&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"video"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
   &lt;span class="c1"&gt;# available types are "image", "video"&lt;/span&gt;
   &lt;span class="n"&gt;newlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"jpeg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"svg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"tif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"tiff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"gif"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s2"&gt;"image"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;newlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mp4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"webm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"avi"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s2"&gt;"video"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;newlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newlist&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_file_YM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="c1"&gt;#eprint(f"Debuglevel {debuglevel}")&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# read exif data&lt;/span&gt;
      &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'rb'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop_tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;#if debuglevel &amp;gt;= 5: eprint(tf,tags["Image DateTime"])&lt;/span&gt;
         &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"['']"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="c1"&gt;# Any other image timestamps could be used here&lt;/span&gt;
      &lt;span class="c1"&gt;#eprint(tags)&lt;/span&gt;
   &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Unable to extract any exif data for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# need to just use timestamp&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromtimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_mtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;# no timestamp available from filesystem?&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"No timestamp available for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_YM_forest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relative_symlinks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;span class="sd"&gt;   For each file in flist, [action] it to outdir, sorting into YYYY/MM subdirs based on exif metadata or timestamp.&lt;/span&gt;
&lt;span class="sd"&gt;   Action may be one of ['symlink', 'copy', 'move'].&lt;/span&gt;
&lt;span class="sd"&gt;   If relative_symlink = True, then make relative symlinks if possible.&lt;/span&gt;
&lt;span class="sd"&gt;   """&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

   &lt;span class="c1"&gt;# validate input&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'symlink'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'copy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'move'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"make_YM_forest action may be one of ['symlink', 'copy', 'move']."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

   &lt;span class="c1"&gt;# Learn all directories to make&lt;/span&gt;
   &lt;span class="c1"&gt;# and also cache the files with Y/M value&lt;/span&gt;
   &lt;span class="n"&gt;fdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
   &lt;span class="n"&gt;destdirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;flist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_file_YM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;#eprint("Stopping due to keyboard variant 2.")&lt;/span&gt;
            &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;#eprint("Stopping due to keyboard variant 1.")&lt;/span&gt;
         &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
         &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;YM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;YM&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;YM&lt;/span&gt;
   &lt;span class="c1"&gt;# finish the for f in flist&lt;/span&gt;

   &lt;span class="c1"&gt;# short-circuit if keyboard action happened in one of the nested functions&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

   &lt;span class="c1"&gt;# Make directories&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;dd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Make dir: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;# Make symlinks&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;ff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
      &lt;span class="n"&gt;basename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;destfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;relative_symlinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;ff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"copy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"cp -p &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"ln -s &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"mv &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;#if False:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"copy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;copy2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;symlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;h4&gt;genlib.py&lt;/h4&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;
&lt;span class="normal"&gt;104&lt;/span&gt;
&lt;span class="normal"&gt;105&lt;/span&gt;
&lt;span class="normal"&gt;106&lt;/span&gt;
&lt;span class="normal"&gt;107&lt;/span&gt;
&lt;span class="normal"&gt;108&lt;/span&gt;
&lt;span class="normal"&gt;109&lt;/span&gt;
&lt;span class="normal"&gt;110&lt;/span&gt;
&lt;span class="normal"&gt;111&lt;/span&gt;
&lt;span class="normal"&gt;112&lt;/span&gt;
&lt;span class="normal"&gt;113&lt;/span&gt;
&lt;span class="normal"&gt;114&lt;/span&gt;
&lt;span class="normal"&gt;115&lt;/span&gt;
&lt;span class="normal"&gt;116&lt;/span&gt;
&lt;span class="normal"&gt;117&lt;/span&gt;
&lt;span class="normal"&gt;118&lt;/span&gt;
&lt;span class="normal"&gt;119&lt;/span&gt;
&lt;span class="normal"&gt;120&lt;/span&gt;
&lt;span class="normal"&gt;121&lt;/span&gt;
&lt;span class="normal"&gt;122&lt;/span&gt;
&lt;span class="normal"&gt;123&lt;/span&gt;
&lt;span class="normal"&gt;124&lt;/span&gt;
&lt;span class="normal"&gt;125&lt;/span&gt;
&lt;span class="normal"&gt;126&lt;/span&gt;
&lt;span class="normal"&gt;127&lt;/span&gt;
&lt;span class="normal"&gt;128&lt;/span&gt;
&lt;span class="normal"&gt;129&lt;/span&gt;
&lt;span class="normal"&gt;130&lt;/span&gt;
&lt;span class="normal"&gt;131&lt;/span&gt;
&lt;span class="normal"&gt;132&lt;/span&gt;
&lt;span class="normal"&gt;133&lt;/span&gt;
&lt;span class="normal"&gt;134&lt;/span&gt;
&lt;span class="normal"&gt;135&lt;/span&gt;
&lt;span class="normal"&gt;136&lt;/span&gt;
&lt;span class="normal"&gt;137&lt;/span&gt;
&lt;span class="normal"&gt;138&lt;/span&gt;
&lt;span class="normal"&gt;139&lt;/span&gt;
&lt;span class="normal"&gt;140&lt;/span&gt;
&lt;span class="normal"&gt;141&lt;/span&gt;
&lt;span class="normal"&gt;142&lt;/span&gt;
&lt;span class="normal"&gt;143&lt;/span&gt;
&lt;span class="normal"&gt;144&lt;/span&gt;
&lt;span class="normal"&gt;145&lt;/span&gt;
&lt;span class="normal"&gt;146&lt;/span&gt;
&lt;span class="normal"&gt;147&lt;/span&gt;
&lt;span class="normal"&gt;148&lt;/span&gt;
&lt;span class="normal"&gt;149&lt;/span&gt;
&lt;span class="normal"&gt;150&lt;/span&gt;
&lt;span class="normal"&gt;151&lt;/span&gt;
&lt;span class="normal"&gt;152&lt;/span&gt;
&lt;span class="normal"&gt;153&lt;/span&gt;
&lt;span class="normal"&gt;154&lt;/span&gt;
&lt;span class="normal"&gt;155&lt;/span&gt;
&lt;span class="normal"&gt;156&lt;/span&gt;
&lt;span class="normal"&gt;157&lt;/span&gt;
&lt;span class="normal"&gt;158&lt;/span&gt;
&lt;span class="normal"&gt;159&lt;/span&gt;
&lt;span class="normal"&gt;160&lt;/span&gt;
&lt;span class="normal"&gt;161&lt;/span&gt;
&lt;span class="normal"&gt;162&lt;/span&gt;
&lt;span class="normal"&gt;163&lt;/span&gt;
&lt;span class="normal"&gt;164&lt;/span&gt;
&lt;span class="normal"&gt;165&lt;/span&gt;
&lt;span class="normal"&gt;166&lt;/span&gt;
&lt;span class="normal"&gt;167&lt;/span&gt;
&lt;span class="normal"&gt;168&lt;/span&gt;
&lt;span class="normal"&gt;169&lt;/span&gt;
&lt;span class="normal"&gt;170&lt;/span&gt;
&lt;span class="normal"&gt;171&lt;/span&gt;
&lt;span class="normal"&gt;172&lt;/span&gt;
&lt;span class="normal"&gt;173&lt;/span&gt;
&lt;span class="normal"&gt;174&lt;/span&gt;
&lt;span class="normal"&gt;175&lt;/span&gt;
&lt;span class="normal"&gt;176&lt;/span&gt;
&lt;span class="normal"&gt;177&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2021-01-29 15:35&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    devuan-req: python3-exifread&lt;/span&gt;
&lt;span class="c1"&gt;# Reference:&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/1192978/python-get-relative-path-of-all-files-and-subfolders-in-a-directory&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/3207219/how-do-i-list-all-files-of-a-directory&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;exifread&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;process_file&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;symlink&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;shutil&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;copy2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# Functions&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;relative&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Listing all files underneath &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"While excluding path matches:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dirnames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
         &lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;indir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
         &lt;span class="n"&gt;use_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
         &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;excludes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# simple match, no regex&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
               &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
               &lt;span class="n"&gt;use_pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
               &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="c1"&gt;# short-circuit&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;relative&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fullpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"ignored per &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;use_pattern&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"video"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
   &lt;span class="c1"&gt;# available types are "image", "video"&lt;/span&gt;
   &lt;span class="n"&gt;newlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"jpeg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"svg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"tif"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"tiff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"gif"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s2"&gt;"image"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;newlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mp4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"webm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"avi"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s2"&gt;"video"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;newlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newlist&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_file_YM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="c1"&gt;#eprint(f"Debuglevel {debuglevel}")&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# read exif data&lt;/span&gt;
      &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'rb'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop_tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;#if debuglevel &amp;gt;= 5: eprint(tf,tags["Image DateTime"])&lt;/span&gt;
         &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Image DateTime"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"['']"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="c1"&gt;# Any other image timestamps could be used here&lt;/span&gt;
      &lt;span class="c1"&gt;#eprint(tags)&lt;/span&gt;
   &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Unable to extract any exif data for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# need to just use timestamp&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromtimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st_mtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;# no timestamp available from filesystem?&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"No timestamp available for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_YM_forest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relative_symlinks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;span class="sd"&gt;   For each file in flist, [action] it to outdir, sorting into YYYY/MM subdirs based on exif metadata or timestamp.&lt;/span&gt;
&lt;span class="sd"&gt;   Action may be one of ['symlink', 'copy', 'move'].&lt;/span&gt;
&lt;span class="sd"&gt;   If relative_symlink = True, then make relative symlinks if possible.&lt;/span&gt;
&lt;span class="sd"&gt;   """&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
   &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

   &lt;span class="c1"&gt;# validate input&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'symlink'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'copy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'move'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
      &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"make_YM_forest action may be one of ['symlink', 'copy', 'move']."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

   &lt;span class="c1"&gt;# Learn all directories to make&lt;/span&gt;
   &lt;span class="c1"&gt;# and also cache the files with Y/M value&lt;/span&gt;
   &lt;span class="n"&gt;fdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
   &lt;span class="n"&gt;destdirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;flist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_file_YM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;debuglevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Y&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;#eprint("Stopping due to keyboard variant 2.")&lt;/span&gt;
            &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;#eprint("Stopping due to keyboard variant 1.")&lt;/span&gt;
         &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
         &lt;span class="k"&gt;break&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;zero_pad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;YM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;YM&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;YM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;YM&lt;/span&gt;
   &lt;span class="c1"&gt;# finish the for f in flist&lt;/span&gt;

   &lt;span class="c1"&gt;# short-circuit if keyboard action happened in one of the nested functions&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

   &lt;span class="c1"&gt;# Make directories&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;destdirs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;dd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Make dir: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;# Make symlinks&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;ff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
      &lt;span class="n"&gt;basename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;destfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;relative_symlinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;ff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debuglevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"copy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"cp -p &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"ln -s &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;eprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"mv &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;dryrun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;#if False:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"copy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;copy2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"symlink"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;symlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;destfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description><category>python</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2021/02/06/symlink-forest-generator/</guid><pubDate>Sat, 06 Feb 2021 14:22:21 GMT</pubDate></item><item><title>Shell: find duplicate files and replace most with symlinks</title><link>https://bgstack15.ddns.net/blog/posts/2020/02/20/shell-find-duplicate-files-and-replace-most-with-symlinks/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;This is probably not the best solution, but it's the one I wanted to work
with. I intended to reduce disk space of 3 similar projects. Here is my shell
script to find duplicate files (by md5sum) and replace any secondary file with
a symlink to the relative path of the original file.&lt;/p&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env sh&lt;/span&gt;
&lt;span class="c1"&gt;# File: set-symlinks.sh&lt;/span&gt;
&lt;span class="c1"&gt;# License: CC-BY-SA 3.0&lt;/span&gt;
&lt;span class="c1"&gt;# Author: bgstack15&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2020-02-07 14:03&lt;/span&gt;
&lt;span class="c1"&gt;# Title: Script that Replaces Duplicate Files with Symlinks&lt;/span&gt;
&lt;span class="c1"&gt;# Purpose:&lt;/span&gt;
&lt;span class="c1"&gt;# History:&lt;/span&gt;
&lt;span class="c1"&gt;# Usage:&lt;/span&gt;
&lt;span class="c1"&gt;# Reference:&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/2564634/convert-absolute-path-into-relative-path-given-a-current-directory-using-bash&lt;/span&gt;
&lt;span class="c1"&gt;# Improve:&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    coreutils &amp;gt;= 8.23&lt;/span&gt;

&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/src/project

&lt;span class="c1"&gt;#results="$( find "${INDIR}" ! -type d ! -type l -exec md5sum {} + | sort )"&lt;/span&gt;
find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ! -type d ! -type l -exec md5sum &lt;span class="o"&gt;{}&lt;/span&gt; + &lt;span class="p"&gt;|&lt;/span&gt; sort &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   awk &lt;span class="s1"&gt;'{a[$1]=a[$1]":"$2} END {for (i in a){print a[i]}}'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -r -e &lt;span class="s1"&gt;'s/^://;'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;':'&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; main child1 child2 child3 child4 &lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; -lt &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;do&lt;/span&gt;
         &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; x &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="k"&gt;))&lt;/span&gt;
         &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nv"&gt;thischild&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"\${child&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;thischild&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="nv"&gt;linkname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; realpath --relative-to &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; dirname &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;thischild&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;/dev/null &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEBUG&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ln -sf &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;linkname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;thischild&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
            &lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DRYRUN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ln -sf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;linkname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;thischild&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
         &lt;span class="k"&gt;fi&lt;/span&gt;
      &lt;span class="k"&gt;done&lt;/span&gt;
   &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;I was going to do this task for myself by hand, but then a quick investigation
showed 73 files that were duplicates. Because of the small size of the
project, I decided to just run it in shell and not revert to Python. I don't
need efficiency; I just need to run it once, really. The tricky bits are in
the very front of the logic. The awk associate array builds a list of all
filenames that correspond with an md5sum. Then, stripping out the leading
colon (separator), I pipe the output to a while for easy variable naming. And
then loop a few times (hard-coded to 4) and if item number X exists, get the
relative path to the main file, and force create the symlink.&lt;/p&gt;</description><category>awk</category><category>files</category><category>loop</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2020/02/20/shell-find-duplicate-files-and-replace-most-with-symlinks/</guid><pubDate>Thu, 20 Feb 2020 14:18:07 GMT</pubDate></item><item><title>python readlink function</title><link>https://bgstack15.ddns.net/blog/posts/2017/09/02/python-readlink-function/</link><dc:creator>bgstack15</dc:creator><description>&lt;h2&gt;tl;dr&lt;/h2&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;def&lt;/span&gt; &lt;span class="nv"&gt;readlinkf&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_inpath&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;:
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;os&lt;/span&gt;.&lt;span class="nv"&gt;path&lt;/span&gt;.&lt;span class="nv"&gt;islink&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;:
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;os&lt;/span&gt;.&lt;span class="nv"&gt;path&lt;/span&gt;.&lt;span class="nv"&gt;join&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;os&lt;/span&gt;.&lt;span class="nv"&gt;path&lt;/span&gt;.&lt;span class="k"&gt;dirname&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_inpath&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;,&lt;span class="nv"&gt;os&lt;/span&gt;.&lt;span class="nv"&gt;readlink&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_inpath&lt;/span&gt;&lt;span class="ss"&gt;))&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;:
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;_inpath&lt;/span&gt;

&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;readlinkf&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;infile&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Explanation&lt;/h2&gt;
&lt;p&gt;In GNU, there's a fantastic utility named &lt;strong&gt;readlink&lt;/strong&gt;. The main way I use it
is to get the full and true path of a file or symlink. For example:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ ls foo .config/qux
.config/qux  foo
$ readlink -f foo
/home/bgstack15/.config/qux
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In python, I wanted to achieve the same thing. it is possible with the
os.path.islink and os.readlink functions. Here is my quick function for a
&lt;strong&gt;readlink -f&lt;/strong&gt; , since I didn't find a specific implementation that outputs
the full path.&lt;/p&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;h2&gt;Weblinks&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/11068419/check-if-file-is-symlink-in-python"&gt;https://stackoverflow.com/questions/11068419/check-if-file-is-symlink-in-python&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Online reference&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/os.path.html#os.path.islink"&gt;https://docs.python.org/3/library/os.path.html#os.path.islink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3.5/library/os.html#os.readlink"&gt;https://docs.python.org/3.5/library/os.html#os.readlink&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Search expressions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://duckduckgo.com/?q=python+detect+if+file+is+symlink"&gt;python detect if file is symlink&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://duckduckgo.com/?q=python+readlink"&gt;python readlink&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><category>python</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2017/09/02/python-readlink-function/</guid><pubDate>Sat, 02 Sep 2017 13:17:23 GMT</pubDate></item><item><title>Shell one-liners for manipulating symlinks</title><link>https://bgstack15.ddns.net/blog/posts/2016/11/22/shell-one-liners-for-manipulating-symlinks/</link><dc:creator>bgstack15</dc:creator><description>&lt;h2&gt;Showing symlink targets&lt;/h2&gt;
&lt;p&gt;I was trying to clean up a directory filled with files and symlinks. Many of
the symlinks' targets did not exist anymore (old package versions). I wrote a
few one-liners to help me examine and clean up the directory. Here's the first
one-liner. &lt;code&gt;find . -type l -print0 | sed -e 's/\.\///g;' | xargs -0 -n1 |
while read line; do canon=$( readlink -f "${line}" 2&amp;gt;/dev/null ); test -e
"${canon}" &amp;amp;&amp;amp; echo "${line} is $( /bin/ls -d --color=always "${canon}" )" ||
echo "INVALID ${line}"; done&lt;/code&gt; In expanded form: &lt;code&gt;find . -type l -print0 | \
sed -e 's/\.\///g;' | \ xargs -0 -n1 | \ while read line; do \ canon=$(
readlink -f "${line}" 2&amp;gt;/dev/null ); test -e "${canon}" &amp;amp;&amp;amp; echo "${line} is $(
/bin/ls -d --color=always "${canon}" )" || echo "INVALID ${line}"; done&lt;/code&gt; The
find command lists symlinks in the current directory, with special null
characters as the separators. This will allow correct operation with spaces in
filenames. You don't normally encounter this in GNU/Linux, but you never know!
The sed removes the dot slash ./ from the beginning of filenames. I just don't
like seeing that. If I had selected find * earlier, I wouldn't need the sed
command, but I would miss any files whose names begin with dot (e.g.,
.gitignore) and I would still find file . which I would have to exclude
somehow anyway (well, not here because I'm searching for symlinks, but I
personally never try to run find * no matter what). xargs -0 -n1 now removes
the null character separators, and feeds each individual entry one at a time
to the next command. While: So for each entry, read the symlink. If the target
is a file, display it in whatever color ls would show it (without entering
directories), because colors are pretty! Otherwise, print the line with
"INVALID" in front of it.&lt;/p&gt;
&lt;h2&gt;Cleaning up the invalid symlinks&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;find . -type l -print0 | sed -e 's/\.\///g;' | xargs -0 -n1 | while read
line; do canon=$( readlink -f "${line}" 2&amp;gt;/dev/null ); test -e "${canon}" &amp;amp;&amp;amp;
true || { echo /bin/rm "./${line}"; }; done&lt;/code&gt; Replace the echo commands with
true for the affirmative and the echo /bin/rm command. To actually effect the
change, remove the echo in front of /bin/rm.&lt;/p&gt;</description><category>oneliner</category><category>shell</category><category>symlink</category><guid>https://bgstack15.ddns.net/blog/posts/2016/11/22/shell-one-liners-for-manipulating-symlinks/</guid><pubDate>Tue, 22 Nov 2016 21:15:23 GMT</pubDate></item></channel></rss>