Added support to extract video taken date from file vs relying alone on modification time
--- /dev/null
+"""
+Create a Plex Playlist with what aired on this day in history (month-day), sort by oldest first.
+If Playlist from yesterday exists delete and create today's.
+If today's Playlist exists exit.
+"""
+
+import operator
+from plexapi.server import PlexServer
+import requests
+import datetime
+
+PLEX_URL = 'http://localhost:32400'
+PLEX_TOKEN = 'xxxxx'
+
+LIBRARY_NAMES = ['Movies', 'TV Shows'] # Your library names
+
+today = datetime.datetime.now().date()
+
+TODAY_PLAY_TITLE = 'Aired Today {}-{}'.format(today.month, today.day)
+
+plex = PlexServer(PLEX_URL, PLEX_TOKEN)
+
+def remove_old():
+ # Remove old Aired Today Playlists
+ for playlist in plex.playlists():
+ if playlist.title.startswith('Aired Today') and playlist.title != TODAY_PLAY_TITLE:
+ playlist.delete()
+ print('Removing old Aired Today Playlists: {}'.format(playlist.title))
+ elif playlist.title == TODAY_PLAY_TITLE:
+ print('{} already exists. No need to make again.'.format(TODAY_PLAY_TITLE))
+ exit(0)
+
+
+def get_all_content(library_name):
+ # Get all movies or episodes from LIBRARY_NAME
+ child_lst = []
+ for library in library_name:
+ for child in plex.library.section(library).all():
+ if child.type == 'movie':
+ child_lst += [child]
+ elif child.type == 'show':
+ child_lst += child.episodes()
+ else:
+ pass
+ return child_lst
+
+
+def find_air_dates(content_lst):
+ # Find what aired with today's month-day
+ aired_lst = []
+ for video in content_lst:
+ try:
+ ad_month = str(video.originallyAvailableAt.month)
+ ad_day = str(video.originallyAvailableAt.day)
+
+ if ad_month == str(today.month) and ad_day == str(today.day):
+ aired_lst += [[video] + [str(video.originallyAvailableAt)]]
+ except Exception as e:
+ # print(e)
+ pass
+
+ # Sort by original air date, oldest first
+ aired_lst = sorted(aired_lst, key=operator.itemgetter(1))
+
+ # Remove date used for sorting
+ play_lst = [x[0] for x in aired_lst]
+ return play_lst
+
+
+remove_old()
+play_lst = find_air_dates(get_all_content(LIBRARY_NAMES))
+# Create Playlist
+if play_lst:
+ plex.createPlaylist(TODAY_PLAY_TITLE, play_lst)
+else:
+ print('Found nothing aired on this day in history.')
+
--- /dev/null
+#!/bin/bash
+# Checks to make sure all videos off of phone have been copied to the Originals directory
+# If they are missing, it means Nextcloud missed them somehow. Copy them to New Memories then.
+
+dcim_path="/storage/emulated/0/DCIM/Camera"
+originals="/naspool/dropbox/Originals"
+new_memories="/naspool/dropbox/New Memories"
+
+adb connect 192.168.0.23
+if [[ $? != 0 ]]; then
+ echo "#ERROR: Unable to connect to phone at 192.168.0.23"
+ exit 1
+fi
+
+mp4s_on_phone=$(adb -e shell ls -1 $dcim_path/*.mp4 | xargs -n 1 basename)
+mp4s_in_originals=$(/bin/ls -1 $originals/*.mp4 | xargs -n 1 basename)
+
+for i in $mp4s_on_phone; do
+ echo "$mp4s_in_originals" | grep -q $i
+ if [[ $? == 1 ]]; then
+ echo "mp4 not found in originals: $i"
+ adb -e pull "$dcim_path/$i" "$new_memories"
+ fi
+done
use DateTime;
use DateTime::Duration;
use DateTime::Format::Duration;
+use DateTime::Format::Strptime qw( );
+
+# Set our ffmpeg creation_time format
+$ffmpeg_time_format = DateTime::Format::Strptime->new(pattern=>'%Y-%m-%dT%H:%M:%S', time_zone => 'UTC', on_error => 'croak');
####################################################################################################
# Configuration parameters
my %videos;
foreach $video (split(/,/, $opt_i)) {
if(! -r "$video") { die "-E- Unable to read input video file: $video\n"; }
- my $mtime_epoch = stat("$video")->mtime;
+ my $mtime_epoch = 0;
+ my $creation_time = `$ffmpeg -i "$video" 2>&1 | grep "creation_time" | head -n 1 | awk '{print \$3}'`;
+ if($creation_time) {
+ my $date_taken = $ffmpeg_time_format->parse_datetime($creation_time);
+ $date_taken->set_time_zone('local');
+ $mtime_epoch = $date_taken->epoch;
+ } else {
+ $mtime_epoch = stat("$video")->mtime;
+ }
my $mdate = epoch_to_date($mtime_epoch);
$videos{$video} = $mtime_epoch;
}
unlink "$video_mp4";
die "-E- handbrake encountered some errors with exit code $errno\n";
}
+ # Restore the metadata from the original video to the intermediate video to preserve the creation_time of the original video metadata in it
+ `$ffmpeg -i \"$video\" -i \"$video_mp4\" -map 1 -map_metadata 0 -c copy -movflags use_metadata_tags \"$video_mp4.fixed.mp4\" >> \"$tmpfile\" 2>&1`;
+ $errno=system("mv \"$video_mp4.fixed.mp4\" \"$video_mp4\" 2>/dev/null");
+ if($errno) { print "-E- Error moving fixed metadata video back to dstfile: $video_mp4.fixed.mp4 -> $video_mp4\n"; }
}
} else {
if($no_recompress) {
my $hour = 0;
my $min = 5;
my $sec = 0;
- my $mtime_epoch = stat("$video")->mtime;
+ my $mtime_epoch = 0;
+ my $creation_time = `$ffmpeg -i "$video" 2>&1 | grep "creation_time" | head -n 1 | awk '{print \$3}'`;
+ if($creation_time) {
+ my $date_taken = $ffmpeg_time_format->parse_datetime($creation_time);
+ $date_taken->set_time_zone('local');
+ $mtime_epoch = $date_taken->epoch;
+ } else {
+ $mtime_epoch = stat("$video")->mtime;
+ }
my $mdate = epoch_to_date($mtime_epoch);
my $duration = `$ffmpeg -i "$video" 2>&1 | grep Duration`;
if($duration =~ /Duration: (\d+):(\d+):(\d+)\.(\d+)/) {
}
print "\n$merge_cmd\n";
if(! defined $opt_s) {
- if(-f "$opt_o.$key.mkv") { die "-E- Output video file $opt_o already exists. This is unexpected for key $key!"; }
+ #if(-f "$opt_o.$key.mkv") { die "-E- Output video file $opt_o already exists. This is unexpected for key $key!"; }
my $errno = system("$merge_cmd");
$errno = $errno >> 8;
if($errno > 1) {
use Getopt::Std;
use File::stat;
use Time::localtime;
+use DateTime::Format::Strptime qw( );
+
+# Set our ffmpeg creation_time format
+$ffmpeg_time_format = DateTime::Format::Strptime->new(pattern=>'%Y-%m-%dT%H:%M:%S', time_zone => 'UTC', on_error => 'croak');
+$ctime_format = DateTime::Format::Strptime->new(pattern=>'%a %b %d %H:%M:%S %Y', time_zone => 'local', on_error => 'croak');
# Early command line options processing
getopts("qzkh:tvs:");
if($srcfile =~ /.hb.mp4/) { next; }
print "Found video: srcdir: $srcdir srcfile: $srcfile srcext: $srcext dstext: $ext\n" if($opt_v);
-
- # Make a note of the month, year, and day this video was taken (from the modification time of the file)
- $date_taken = ctime(stat("$srcdir/$srcfile")->mtime);
-
+
+ # Make a note of the month, year, and day this video was taken
+ $creation_time = `$ffmpeg -i "$srcdir/$srcfile" 2>&1 | grep "creation_time" | head -n 1 | awk '{print \$3}'`;
+ if($creation_time) {
+ $date_taken = $ffmpeg_time_format->parse_datetime($creation_time);
+ } else {
+ # From the modification time of the file since we couldn't find it in the video file
+ $date_modified = ctime(stat("$srcdir/$srcfile")->mtime);
+ }
+
+ # Get the date taken from the ffmpeg creation_time
+ if(!$merge_by_modification_time && $date_taken) {
+ $date_taken->set_time_zone('local');
+ $year = $date_taken->year;
+ $month = sprintf("%02d",$date_taken->month);
+ $day = sprintf("%02d",$date_taken->day);
+ $monthnum = sprintf("%02d",$date_taken->month);
+ $monthname = lc($month2monthname{$month});
+ #print "date_taken: $year-$month-$day ".$date_taken->hour.":".$date_taken->minute.":".$date_taken->second." ".$date_taken->time_zone."\n";
+ }
# Get the date taken from the filename
- if(!$merge_by_modification_date && $srcfile =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/) {
+ elsif(!$merge_by_modification_date && $srcfile =~ /^(\d\d\d\d)-(\d\d)-(\d\d)/) {
$year = $1;
$month = $2;
$day = sprintf("%02d",$3);
$monthname = lc($month2monthname{$month});
}
# Get the date taken from the modification time
- elsif($date_taken =~ /\S+\s+(\S+)\s+(\d+)\s+\S+\s+(\d+)/) {
+ elsif($date_modified =~ /\S+\s+(\S+)\s+(\d+)\s+\S+\s+(\d+)/) {
$year = $3;
$month = $1;
$day = sprintf("%02d",$2);
--- /dev/null
+#!/bin/bash
+
+SRC=$1
+NAME="${SRC%.*}"
+MPG="${NAME}.mpg"
+DVD="${NAME}.dvd"
+ISO="${NAME}.iso"
+
+export VIDEO_FORMAT=NTSC
+
+if [[ -z $SRC ]] || [[ ! -r $SRC ]]; then
+ echo "-E- You need to specify a valid src video file as an argument"
+ exit 1
+fi
+
+if [[ ! -e "$MPG" ]]; then
+ echo "-> Converting \"$SRC\" -> \"$MPG\""
+ # Convert the SRC video into a DVD compatible mpg2 file
+ ffmpeg -i "$SRC" -target ntsc-dvd -aspect 16:9 "$MPG"
+ if [[ $? != 0 ]]; then
+ echo "-> ffmpeg encountered an error. aborting..."
+ rm "$MPG"
+ exit 1;
+ fi
+fi
+
+echo "-> Creating DVD ISO: $ISO"
+# Create an intermediate DVD dir
+mkdir -p "$DVD"
+# Define the title file
+dvdauthor -o "$DVD" -t "$MPG"
+# Create a table of contents
+dvdauthor -o "$DVD" -T
+# Convert the DVD dir into an ISO image
+genisoimage -dvd-video -o "$ISO" "$DVD"
+# Remove the intermediate DVD dir
+rm -rf "$DVD"
+# Remove the intermediate MPG file
+rm "$MPG"
}
# Make sure we have a unique dstfile
- if(-f "$dstfile") {
+ if($overwrite_dest == 0 && -f "$dstfile") {
$video_ext = $srcfile;
$video_ext =~ s/.*\.(\S+)$/$1/;
$suffix = 0;
if(!defined $opt_t) {
# Make sure the dstfile doesn't exist, if it does, add a unique number to the end
- if(! -f "$dstfile") {
- $errno=system("mv \"$srcdir/$srcfile\" \"$dstfile\" 2>/dev/null");
- if($errno) { print "-E- Error moving srcfile to dstfile: $srcdir/$srcfile -> $dstfile\n"; next; }
- } else {
- print "-E- Unable to mv $srcdir/$srcfile -> $dstfile because it already exists\n";
- }
+ #if(! -f "$dstfile") {
+ $errno=system("mv \"$srcdir/$srcfile\" \"$dstfile\" 2>/dev/null");
+ if($errno) { print "-E- Error moving srcfile to dstfile: $srcdir/$srcfile -> $dstfile\n"; next; }
+ #} else {
+ # print "-E- Unable to mv $srcdir/$srcfile -> $dstfile because it already exists\n";
+ #}
# Fix the permissions
system("chown $owner \"$dstfile\"");
system("chgrp $group \"$dstfile\"");
system("chmod $mode \"$dstfile\"");
}
}
+
+ # Update nextcloud file cache so it knows what files we have moved
+ $watchpath =~ s/$nextcloudbase//g;
+ system("$occ files:scan --path \"$watchpath\" > /dev/null");
}
$pidfile->remove();
print "srcfile: $srcfile\n";
if($srcfile =~ /.hb.mp4/) { next; }
- print "Found movie: srcdir: $srcdir srcfile: $srcfile ext: $ext\n" if($opt_v);
-
- # Make a note of the month, year, and day this video was taken (from the modification time of the file)
- $date_taken = ctime(stat("$srcdir/$srcfile")->mtime);
+ print "Found video: srcdir: $srcdir srcfile: $srcfile ext: $ext\n" if($opt_v);
+
+ # From the modification time of the file since we couldn't find it in the filename
+ $date_modified = ctime(stat("$srcdir/$srcfile")->mtime);
+
+ # NOTE: This file matching algorithm only applies to videos produced by merge_videos_by_day called by this script earlier
+ # We just need to take those merged videos, and extract what date to call the video by under HomeVideos
# Get the date taken from the filename
if($srcfile =~ /^(\d+)-(\d+)-(\d+)/) {
$monthname = lc($month2monthname{$month});
}
# Get the date taken from the modification time
- elsif($date_taken =~ /\S+\s+(\S+)\s+(\d+)\s+\S+\s+(\d+)/) {
+ elsif($date_modified =~ /\S+\s+(\S+)\s+(\d+)\s+\S+\s+(\d+)/) {
$year = $3;
$month = $1;
$day = sprintf("%02d",$2);
# Path to a dir (or dirs separated by semis) to watch for videos to move to $srcpathname to be organized
$watchpathname = "/naspool/cloud/alan/files/InstantUpload/Camera;/naspool/cloud/mary/files/InstantUpload/Camera;";
+# Path to nextcloud base dir where user dirs start
+$nextcloudbase = "/naspool/cloud/";
+
+# If there are file duplicates in srcpathname, should they be overwritten (assumes all files from phones will be named uniquely)
+$overwrite_dest = 1;
+
+# Path to nextcloud occ cmd script
+$occ = "/naspool/www/pippins.net/nextcloud.custom/occ.cmd";
+
# Path to merge_videos_by_day script
$merge_videos_by_day = "/naspool/videos/bin/merge_videos_by_day";
# Flag to merge videos by modification date instead of the date parsed from the filename
-$merge_by_modification_date = 1;
+$merge_by_modification_date = 0;
# Path to the make_mkv script
$make_mkv = "/naspool/videos/bin/make_mkv";
# Video file creation dates must not have changed in the last X minutes to process any of the video files
# This is done to ensure that all videos from a given upload from a camera have completed prior to looking for videos to merge
-$minage = "+120";
+$minage = "+60";
# What command should be used to find files that have changed (are at least $minage old)
$find_changed_cmd = "find \"$srcpathname/\" -not -cmin $minage -a \\( $movie_file_ext \\)";
--- /dev/null
+#!/usr/bin/perl
+# Author: Alan J. Pippin
+# Description: Find and remove TV recording directories that don't contain any recordings in them
+
+use File::Copy;
+use File::Basename;
+use Getopt::Std;
+use File::stat;
+use Time::localtime;
+use File::Pid;
+use Data::Dumper;
+
+####################################################################################################
+# Configuration parameters
+my $tv_src_dir = "/tvpool/tv";
+my $log = "/var/log/organize/remove_empty_tv_dirs.log";
+my $tv_file_ext = "-iregex \".*\.mov\" -o -iregex \".*\.avi\" -o -iregex \".*\.mp4\" -o -iregex \".*\.mpg\" -o -iregex \".*\.ts\" -o -iregex \".*\.mkv\"";
+my $find_tv_show_dirs = "find \"$tv_src_dir/\" -maxdepth 1 -cmin +14400 -type d";
+my $find_tv_season_dirs = "find \"$tv_src_dir/\" -maxdepth 2 -mindepth 2 -cmin +14400 -type d";
+my $find_tv_shows = "find \"$tv_src_dir/\" -cmin +14400 $tv_file_ext";
+
+####################################################################################################
+# Find empty TV show directories to remove
+
+my %tv_show_dirs;
+
+# Find all of our TV season dirs and store them in a hash
+foreach $dir (`$find_tv_season_dirs`) {
+ chomp($dir);
+ my $season = basename($dir);
+ my $show = basename(dirname($dir));
+ #print "-> Found dir $dir show $show season $season\n";
+ $tv_show_dirs{$show}{$season}{has_recordings} = 0;
+}
+foreach $dir (`$find_tv_show_dirs`) {
+ chomp($dir);
+ my $show = basename($dir);
+ #print "-> Found dir $dir show $show\n";
+ $tv_show_dirs{$show}{has_recordings} = 0;
+}
+
+# Find all of our TV show recordings and store them in a hash
+foreach $file (`$find_tv_shows`) {
+ chomp($file);
+ my $recording = basename($file);
+ my $season = basename(dirname($file));
+ my $show = basename(dirname(dirname($file)));
+ #print "-> Found show $show season $season and recording $recording\n";
+ $tv_show_dirs{$show}{$season}{has_recordings} = 1;
+ $tv_show_dirs{$show}{has_recordings} = 1;
+}
+
+#print Dumper(\%tv_show_dirs);
+
+# For each season directory that doesn't have recordings, remove it
+foreach $show (keys %tv_show_dirs) {
+ foreach $season (keys %{$tv_show_dirs{$show}}) {
+ if($season eq "has_recordings") { next; }
+ if ($tv_show_dirs{$show}{$season}{has_recordings} == 0) {
+ print "-> Removing season dir '$show/$season'\n";
+ system("rm -rf \"$tv_src_dir/$show/$season/\"");
+ }
+ }
+}
+
+# For each show directory that doesn't have any recordings under it, remove it
+foreach $show (keys %tv_show_dirs) {
+ my $has_recordings = 0;
+ if($show eq ".grab") { next; }
+ foreach $season (keys %{$tv_show_dirs{$show}}) {
+ if ($tv_show_dirs{$show}{$season}{has_recordings} == 1) {
+ $has_recordings = 1;
+ }
+ }
+ if($has_recordings == 0) {
+ print "-> Removing show dir '$show'\n";
+ system("rm -rf \"$tv_src_dir/$show/\"");
+ }
+}