m (History)
m (History)
 
(6 intermediate revisions by one user not shown)
Line 7: Line 7:
 
== Usage ==
 
== Usage ==
  
Copy the file <tt>sopi.jl</tt> in the directory where the directory tree is to be formed and files redistributed, then run:
+
Install <tt>sopi</tt> in a binary directory (e.g., /usr/bin) as an executable; It relies on exiftool which can be installed with <tt>sudo apt install libimage-exiftool-perl</tt>.
 +
 
 +
Run on the destination directory:
  
 
<pre>
 
<pre>
julia sopi.jl
+
sopi /home/laussy/pics/
 
</pre>
 
</pre>
  
Work on a copy!
+
<tt>Sopi</tt> won't run if not given a directory. To work in the current directory:
 +
 
 +
<pre>
 +
sopi .
 +
</pre>
 +
 
 +
To work on various directories, put them in a file <tt>dirs.txt</tt> and call
 +
 
 +
<pre>
 +
cat dirs.txt | xargs -I '{}' sopi {}
 +
</pre>
  
 
== History ==
 
== History ==
Line 19: Line 31:
 
* [[:File:sopi-v0.1.jl.gz|v0°1]] on {{thisday|10|October|2020}}. Simplest features.
 
* [[:File:sopi-v0.1.jl.gz|v0°1]] on {{thisday|10|October|2020}}. Simplest features.
 
* [[:File:sopi-v0.11.jl.gz|v0°11]] on {{thisday|1|November|2020}}. Numbered-months (01-January, etc.), pretty-labelling of dates & fix a bug for May.
 
* [[:File:sopi-v0.11.jl.gz|v0°11]] on {{thisday|1|November|2020}}. Numbered-months (01-January, etc.), pretty-labelling of dates & fix a bug for May.
 +
* [[:File:sopi.gz|v0°2]] on {{thisday|1|January|2021}}. Standalone version (no need to copy the script) processing working directory as an argument.
 +
* [[:file:sopi.gz|v0°3]] on {{thisday|5|January|2024}}. [[Blog:Hacks/Debugging_sopi|Fixed a bug]] for some images with invalid timestamps.
  
 
== Todo ==
 
== Todo ==
  
Failsafe, options (path to files, extensions, ...)
+
There should be an option to add the timestamp to the image itself which can be done by hand by uncommenting the following:
 +
 
 +
<pre>
 +
#    mv(lfn[i],dest[1]*lmonths[:,2][parse(Int64,dest[2])]*dest[3]*"/"*replace(replace(lfn[i],".JPG"=>"-"),".jpg"=>"-")*alltimes[i,2]*".jpg")
 +
</pre>
 +
 
 +
This is not needed for photos that come from the phone, which are already tagged, but is necessary for those of the camera.
  
 
== Source ==
 
== Source ==
  
 
<pre>
 
<pre>
 +
#!/bin/sh
 
#  ____              _  
 
#  ____              _  
 
# / ___|  ___  _ __ (_)
 
# / ___|  ___  _ __ (_)
Line 32: Line 53:
 
#  ___) | (_) | |_) | |
 
#  ___) | (_) | |_) | |
 
# |____/ \___/| .__/|_|
 
# |____/ \___/| .__/|_|
# v°0.11      |_|       
+
# v°0.2      |_|       
# Sun 1 Nov 15:28:17 CET 2020
+
# Fri 1 Jan 18:50:20 CET 2021
 
# F.P. Laussy - fabrice.laussy@gmail.com
 
# F.P. Laussy - fabrice.laussy@gmail.com
 
#  
 
#  
Line 39: Line 60:
 
# at which the pictures have been taken (after their exif data)
 
# at which the pictures have been taken (after their exif data)
 
# (`sopi' stands for Sort Pictures)
 
# (`sopi' stands for Sort Pictures)
 +
#
 +
#=
 +
exec julia -O3 "$0" -- $@
 +
=#
  
 
using Dates;
 
using Dates;
  
 +
# Goes to given directory if one is given as argument
 +
# If not argument given, exit (for safety)
 +
if length(ARGS)!=0
 +
  cd(ARGS[1])
 +
  else
 +
      println("The working directory must be given as argument")
 +
      println("To process files in the current directory, use:")
 +
      println(" sopi .")
 +
      exit()
 +
end
 +
     
 
# This list the filenames of JPG files to process (in current path)
 
# This list the filenames of JPG files to process (in current path)
 
lfn=filter(x->occursin("JPG",x), readdir());
 
lfn=filter(x->occursin("JPG",x), readdir());
  
 
# Starting
 
# Starting
print("Hi there! Sopi working with "*string(length(lfn))*" files...\n")
+
println("Hi there! Sopi working with "*string(length(lfn))*" files in "*pwd())
  
 
print("Started ");
 
print("Started ");

Latest revision as of 15:41, 5 January 2024

Contents

Sopi

Sopi (Sort Pictures) is a simple Julia program written by Fabrice that takes a list of files from our camera (with extension "JPG") and move them in a directory tree named after the date, also appending the hour of the shot to the filename itself.

This replaces the script SortTime which we were using until then but that was taking too much time to be convenient (over a second per file). Testing on 563 files from our last batch of pictures, it reduced the 17min37s of SortTime to 1min9s, which is more reasonable!

Usage

Install sopi in a binary directory (e.g., /usr/bin) as an executable; It relies on exiftool which can be installed with sudo apt install libimage-exiftool-perl.

Run on the destination directory:

sopi /home/laussy/pics/

Sopi won't run if not given a directory. To work in the current directory:

sopi .

To work on various directories, put them in a file dirs.txt and call

cat dirs.txt | xargs -I '{}' sopi {}

History

Todo

There should be an option to add the timestamp to the image itself which can be done by hand by uncommenting the following:

#    mv(lfn[i],dest[1]*lmonths[:,2][parse(Int64,dest[2])]*dest[3]*"/"*replace(replace(lfn[i],".JPG"=>"-"),".jpg"=>"-")*alltimes[i,2]*".jpg")

This is not needed for photos that come from the phone, which are already tagged, but is necessary for those of the camera.

Source

#!/bin/sh
#  ____              _ 
# / ___|  ___  _ __ (_)
# \___ \ / _ \| '_ \| |
#  ___) | (_) | |_) | |
# |____/ \___/| .__/|_|
# v°0.2       |_|      
# Fri  1 Jan 18:50:20 CET 2021
# F.P. Laussy - fabrice.laussy@gmail.com
# 
# Sopi sorts jpg files in a directory tree named after the dates
# at which the pictures have been taken (after their exif data)
# (`sopi' stands for Sort Pictures)
#
#=
exec julia -O3 "$0" -- $@
=#

using Dates;

# Goes to given directory if one is given as argument
# If not argument given, exit (for safety)
if length(ARGS)!=0
   cd(ARGS[1])
   else
       println("The working directory must be given as argument")
       println("To process files in the current directory, use:")
       println(" sopi .")
       exit()
end
       
# This list the filenames of JPG files to process (in current path)
lfn=filter(x->occursin("JPG",x), readdir());

# Starting
println("Hi there! Sopi working with "*string(length(lfn))*" files in "*pwd())

print("Started ");
print(now());
print("\n")

# This returns a vector with date and time from the exif data
function datemy(fn)
 mdata = read(`exiftool $fn`,String)
 sdata=split(mdata,"\n")
 spdata=split(sdata[findall( x -> occursin("Date/Time Original", x) , split(mdata,"\n"))[1]]," ")
 [spdata[end-1],spdata[end]]
end

# This collects all the dates and times to process and transform into a matrix
alltimes=permutedims(reduce(hcat,[datemy(i) for i in lfn]))

# Keep unique days
uniquetimes=(x->replace(x, ":"=>"/")).(unique(alltimes[:,1]))

# This creates the directory tree
lmonths=["/01/" "/01-January/"; "/02/" "/02-February/"; "/03/" "/03-March/"; "/04/" "/04-April/"; "/05/" "/05-May/"; "/06/" "/06-June/"; "/07/" "/07-July/"; "/08/" "/08-August/"; "/09/" "/09-September/"; "/10/" "/10-October/"; "/11/" "/11-November/"; "/12/" "/12-December/"]

for i=1:12
 global uniquetimes=(x->replace(x,lmonths[i,1]=>lmonths[i,2])).(uniquetimes[:,1])
end

print("Working with "*string(length(uniquetimes))*" directories...\n")
mkpath.(uniquetimes)

print("Moving files!\n")
# This puts the files in pla
for i=1:length(lfn)
 dest=split(alltimes[i,1],":")
 mv(lfn[i],dest[1]*lmonths[:,2][parse(Int64,dest[2])]*dest[3]*"/"*replace(lfn[i],".JPG"=>"-")*alltimes[i,2]*".JPG")
end

print("Finished ")
print(now())
print("\n")