7

I want to have my wallpaper be seasonal (summer, fall, winter, spring), but also update daily with a seasonal themed wallpaper.

So essentially, I am thinking of having 4 directories (summer, fall, winter, spring). During summer, my wallpaper background would rotate through the images in the summer directory on a daily basis. Then on Sept. 21, the wallpaper directory would change to fall, and the wallpaper would then cycle through those images on a daily basis, etc.

I am comfortable writing a script, but where would I start?

How this question is unique

Edit: To clarify further about what makes this question unique. While there are many methods to create a slideshow, they all depend on setting the images directory. What I am asking is how to dynamically change the images directory. So slide show today comes out of the /images/winter/ directory, and slide show in spring comes out of the /images/spring/ directory. I could manually do this by just changing the directory in the appearance settings every season, but I don't want to have to that when I can tell the computer to do it for me.

0

5 Answers 5

4

Introduction

The basic question is how to do something at the start of Spring, Summer, Fall and Winter. For this I would create a bash script that runs on boot, rather than clogging up cron with entries.

I've approached this answer using the OP's question "How do I develop a script?". So I've deviated from usual method of simply posting a bash script and enhanced the answer with:

  • References are included within the code. They link to Stack Exchange answers for solving specific problems. For example: How to copy files, How to get day of year, etc.
  • A section on "Testing" is provided as it is something we all need to do
  • A section on "Enhancements" is provided because software is usually developed in versions where each is incrementally better than the previous version.

When do seasons start?

From the Farmer's Almanac:

Seasons of 2018

Season Astronomical Start Meteorological Start
SPRING Tuesday, March 20, 12:15 P.M. EDT Thursday, March 1
SUMMER Thursday, June 21, 6:07 A.M. EDT Friday, June 1
FALL Saturday, September 22, 9:54 P.M. EDT Saturday, September 1
WINTER Friday, December 21, 5:23 P.M. EST Saturday, December 1

Convert season start date to Day of Year

For our bash script to work we need to know what day of the year each seasons start.

$ echo $(date --date="March 20" '+%j')
079
$ echo $(date --date="June 21" '+%j')
172
$ echo $(date --date="Sep 22" '+%j')
265
$ echo $(date --date="Dec 21" '+%j')
355
# Reference: https://unix.stackexchange.com/questions/352176/take-input-arguments-and-pass-them-to-date

Create bash script: season.sh

Open the terminal using: Ctrl+Alt+T

Create the directory if it doesn't exist: mkdir -p ~/bin

Edit the script using: gedit ~/bin/season.sh

  • Note: Lubuntu user's need to use leafpad instead of gedit

Copy and paste the following lines into gedit:

#!/bin/bash
# NAME: season.sh
# PATH: ~/bin
# DATE: December 15, 2018

# NOTE: Written for: https://askubuntu.com/questions/1100934/change-dynamic-wallpaper-directory-every-season/1102084#1102084

# User defined variables, change to suit your needs
# Our directory names, lines indented for cosmetic reasons only
SlideShowDir="~/Season Slide Show"
   SpringDir="~/Pictures/Spring Slide Show"
   SummerDir="~/Pictures/Summer Slide Show"
     FallDir="~/Pictures/Fall Slide Show"
   WinterDir="~/Pictures/Winter Slide Show"

CheckTripWire () {
    # Our last season is in "~/Season Slide Show/CurrentSeason"
    LastSeasonFilename="$SlideShowDir"/CurrentSeason
    LastSeason=$(cat "$LastSeasonFilename")
    
    [[ "$LastSeason" == "$Season" ]] && return 0 # Season still the same
    
    # We now know our season has changed.
    
    rm -f "$SlideShowDir"/{*,.*}           # Erase all files in target
    # Reference: https://askubuntu.com/questions/60228/how-to-remove-all-files-from-a-directory
    
    echo "$Season" > "$LastSeasonFilename" # Record new season in target
    
    # Copy new slide show based on season
    if (( "$Season" == SPRING)) ; then
        cp -R "$SpringDir"/. "$SlideShowDir"/
        # Reference: https://stackoverflow.com/questions/3643848/copy-files-from-one-directory-into-an-existing-directory
    elif (( "$Season" == SUMMER)) ; then
        cp -R "$SummerDir"/. "$SlideShowDir"/
    elif (( "$Season" == FALL)) ; then
        cp -R "$FallDir"/. "$SlideShowDir"/
    else
        cp -R "$WinterDir"/. "$SlideShowDir"/
    fi

} # End of CheckTripWire () function.

# Start of Mainline

DOY=$(date '+%j')                     # DOY = Current Day of Year
# Reference: https://stackoverflow.com/questions/10112453/how-to-get-day-of-the-year-in-shell

if ((DOY>=079 && DOY<172)) ; then
    Season="SPRING"                   # Spring has sprung!
    # Reference: https://stackoverflow.com/questions/12614011/using-case-for-a-range-of-numbers-in-bash
elif ((DOY>=172 && DOY<265)) ; then
    Season="SUMMER"                   # Hit the beach!
elif ((DOY>=265 && DOY<355)) ; then
    Season="FALL"                     # Rake those leaves!
else
    Season="WINTER"                   # Shovel the snow!
fi

# Current season establish, now see if we tripped the wire
CheckTripWire

exit 0 # Command not necessary but good habit to signify no Abend.

Save the file in gedit. Now mark it as executable using:

chmod a+x ~/bin/season.sh

Next we need to add it to startup applications. Reference: How do I start applications automatically on login?

Note: You probably already have your slide show setup in startup applications. You will want to use season.sh BEFORE your regular slide show as it deletes and copies files which would crash the slide show program if it started first.


Testing

You will want to test season.sh script when you create it and not wait a year to see if it works properly or not. Reference: Faking the date for a specific shell session


Enhancements

After initially developing a script it is common to enhance it Days, Weeks, Months or even Years later. This section discusses some enhancements you might want to make to session.sh down the road.

Compress files to save disk space

Consider keeping the off-season images compressed in TAR (Tape Archive) format to save on disk space. Then replace the cp (Copy) command with the tar command to uncompress the files. Reference: 23 tar Command Examples For Linux:

For example, we would change:

cp -R "$SpringDir"/. "$SlideShowDir"/

To:

tar -xf "$SpringDir"archive.tar -C "$SlideShowDir"/

... and so on for the other seasons.

Setup variables for season start

Using variables for season start days makes it easier to modify the script and makes the code easier to read (aka code readability).

Consider setting up Variables for start of season:

SpringStart=079
SummerStart=179
FallStart=265
WinterStart=355

Define the variables at the top of the script to make them easier to spot and change. You might want to do this for leap years. You might want to change to "Meteorological" season starts instead of "Astronomical" start dates.

Then change these lines:

if ((DOY>=079 && DOY<172)) ; then
elif ((DOY>=172 && DOY<265)) ; then
elif ((DOY>=265 && DOY<355)) ; then

To this:

if ((DOY>="$SpringStart" && DOY<"$SummerStart")) ; then
elif ((DOY>="$SummerStart" && DOY<"$FallStart")) ; then
elif ((DOY>="$FallStart" && DOY<"$WinterStart")) ; then
3
  • @PRATAP I regret I didn't get the whole answer completely polished in two hours but enough is there to answer your comment I believe. Dec 15, 2018 at 15:32
  • Thanks for the answer. I accepted this because 1) I needed to practice with bash and it was a great tutorial, and 2) It was really complete and well laid out. Utlimately, I combined it with @unutbu answer to just change a symbolic link instead of copying and pasting files. Here is a gist with the code. If you just want a simple method to do this without creating a script, I think @unutbu answer is probably the way to go. Dec 17, 2018 at 22:21
  • @JosephGilgen I agree the cron method is simplest and up-voted it. I approached the question as requiring a scripting answer with the objective of teaching a little scripting along the way. I included references to other Stack Exchange answers to show where the theory / implementation of different coding techniques come from. It was a thoroughly enjoyable project and I thank you for posting the question. Which I also hopes garners many upvotes :) Dec 17, 2018 at 23:18
2

Perhaps this is an easier way:

  1. Create a symlink from ~/images/mybackgrounds to ~/images/spring:

    ln -s ~/images/spring ~/images/mybackgrounds
    
  2. Use one of these methods to display a background slideshow using images from ~/images/mybackgrounds.

  3. Set up crontab entries to change the symlink on particular days. Create a file called ~/mycrontab with these contents:

    # min  hr     day     mon  dow
    0      9      21      3    *     ln -sf ~/images/spring ~/images/mybackgrounds
    0      9      21      6    *     ln -sf ~/images/summer ~/images/mybackgrounds
    0      9      21      9    *     ln -sf ~/images/fall ~/images/mybackgrounds
    0      9      21      12   *     ln -sf ~/images/winter ~/images/mybackgrounds
    

    Run

    crontab ~/mycrontab
    

    to register the crontab entries. On March 21 at 9AM, crond will run the command

    ln -sf ~/images/spring ~/images/mybackgrounds
    

thus linking ~/images/mybackgrounds to ~/images/spring. On Jun 21 at 9AM, crond will change the symlink so that ~/images/mybackgrounds points to ~/images/summer. The slideshow program is configured to select a file from ~/images/mybackgrounds. The path to ~/images/mybackgrounds stays the same, but now all the contents are different because the symlink points to a different location. The crontab entries for Sep 21 and Dec 21 pull the same trick.

2
  • This is really the most simple and straight forward method to accomplish what I was trying to do. No scripting, just updating the slideshow directory with a cron job. While I accepted the answer from @WinEunuuchs2Unix, perhaps upvotes will really show this to be the most useful answer. Dec 17, 2018 at 22:24
  • Upvote from me :) Dec 17, 2018 at 23:15
0

Step 1: Create a slideshow.py script

Save this in a file called ~/bin/slideshow.py:

#!/usr/bin/env python
import os
import datetime as DT
import itertools as IT
import bisect
import random
import subprocess

# customize cutoffs and image_dirs however you like, but note that there must be
# the same number of items in each, and the items in cutoffs must be in sorted order.
cutoffs = [(3, 21), (6, 21), (9, 21), (12, 21)]
image_dirs = ['~/images/winter', '~/images/spring', '~/images/summer', '~/images/fall']
image_dirs = list(map(os.path.expanduser, image_dirs))

today = DT.date.today()
year = today.year

# convert the cutoffs to actual dates
cutoff_dates = [DT.date(year, m, d) for m, d in cutoffs]
# find the index into cutoff_dates where today would fit and still keep the list sorted
idx = bisect.bisect(cutoff_dates, today)
# use idx to get the corresponding image directory 
image_dir = next(IT.islice(IT.cycle(image_dirs), idx, idx+1))

# list all the files in image_dir (even in subdirectories, and following symlinks)
files = [os.path.join(root, filename)
         for root, dirs, files in os.walk(image_dirs[idx], followlinks=True)
         for filename in files]
# pick a file at random
imagefile = os.path.abspath(random.choice(files))

# find the current process's effective user id (EUID)
euid = str(os.geteuid())
# find the pid of the current EUID's gnome-session
pid = subprocess.check_output(['pgrep', '--euid', euid, 'gnome-session']).strip().decode()
# load all the environment variables of gnome-session
env = open('/proc/{}/environ'.format(pid), 'rb').read().strip(b'\x00')
env = dict([item.split(b'=', 1) for item in env.split(b'\x00')])
# get the value of DBUS_SESSION_BUS_ADDRESS environment variable
key = b'DBUS_SESSION_BUS_ADDRESS'
env = {key: env[key]}
# call gsettings to change the background to display the selected file
# with the DBUS_SESSION_BUS_ADDRESS environment variable set appropriately
subprocess.call(['gsettings', 'set', 'org.gnome.desktop.background', 'picture-uri',
                 'file://{}'.format(imagefile)], env=env)

Step 2: Make it executable:

chmod 755 ~/bin/slideshow.py

To test that things are working as expected, you can open a terminal and run slideshow.py repeatedly. You should see the background changing. Note that slideshow.py looks for images in one of 4 directories, ~/images/spring, ~/images/summer, ~/images/fall, or ~/images/winter depending on the season.

Step 3: Configure crontab

You can use cron to periodically run a command to change the background, say, once every day or once every minute minutes.

Make a file called, say, ~/mycrontab, and put something like this inside:

# min  hr     day     mon  dow
# 0      9      *       *    *    ~/bin/slideshow.py   # run once at 9AM
*      *      *       *    *    ~/bin/slideshow.py   # run once every minute

Then run

crontab ~/mycrontab

to register the change to your crontab.

You should now see the background changing once every minute. (You might even enjoy keeping it this way.)

crontab will ignore lines which begin with #. So if you want the background to change once per day, uncomment the second line and comment-out the third so that ~/mycrontab now looks like this:

# min  hr     day     mon  dow
0      9      *       *    *    ~/bin/slideshow.py   # run once at 9AM
# *      *      *       *    *    ~/bin/slideshow.py   # run once every minute

Note however that cron will only run this command if you are logged into the machine at 9AM that day.

3
  • I like the direction this is going. I have not had a chance to play with it yet. What I am trying to do though is change the directory every season, so it would be something like /path/to/spring/*.png in spring, but I don't quite think that would work. Dec 14, 2018 at 22:29
  • Hope you don't mind but I edited your answer to use Python Language highlighting. I also changed chown to chmod which I think was your original intent. Dec 15, 2018 at 18:18
  • @WinEunuuchs2Unix: Thanks for the corrections.
    – unutbu
    Dec 15, 2018 at 18:20
0
  1. Create a folder SeasonalWallPapers in home directory ~/SeasonalWallPapers
  2. Create subfolders in ~/SeasonalWallPapers Fall, Spring, Summer & Winter.
    • Keep only .jpg files in the above four folders as the script is modified only to take .jpg files

enter image description here

  • Please note the in the below images .xml files are generated by scripts. You don't need to create/ worry about it.

enter image description here

enter image description here

enter image description here

enter image description here

  1. Create 4 Scripts with below content in each of the four folders above.
    FWP.sh, RWP.sh, SWP.sh & WWP.sh

Note: change the 3rd line in the below script FILE="FWP.xml" in other three script files to make them FILE=RWP.xml, FILE=SWP.xml & FILE=WWP.xml.

Note: in the below script Duration is set to 2 seconds only. in actual for every day change of wall paper, set it to 86400

#!/bin/bash

FILE="FWP.xml"
DURATION=2.0
TRANSITION=0.0

CURRENTDIR=$PWD
TRANSITION_XML="
<static>
    <duration>$DURATION</duration>
    <file>$CURRENTDIR/%s</file>
</static>
<transition>
    <duration>$TRANSITION</duration>
    <from>$CURRENTDIR/%s</from>
    <to>$CURRENTDIR/%s</to>
</transition>
"

# Random order
IMGS=( *.jpg )
INDICES=( $(shuf -e ${!IMGS[@]}) ) # randomize indices of images
INDICES+=(${INDICES[0]})           # go back to first image after last
COUNTER=${#IMGS[@]}

exec > "$FILE"                     # all further output to the XML file
echo "<background><starttime></starttime>"

for ((i = 0; i < COUNTER; i++))
do
    index=${INDICES[i]}
    printf "$TRANSITION_XML" "${IMGS[index]}" "${IMGS[index]}" "${IMGS[index + 1]}"
done

echo "</background>"
  1. make the scrips executable with

chmod +x ~/SeasonalWallPapers/Fall/FWP.sh
chmod +x ~/SeasonalWallPapers/Spring/RWP.sh
chmod +x ~/SeasonalWallPapers/Summer/SWP.sh
chmod +x ~/SeasonalWallPapers/Winter/WWP.sh

  1. Create a script called WP.sh with below content.
#! /bin/bash

cd ~/SeasonalWallPapers/Summer/ && ./SWP.sh
cd ~/SeasonalWallPapers/Fall/ && ./FWP.sh
cd ~/SeasonalWallPapers/Winter && ./WWP.sh
cd ~/SeasonalWallPapers/Spring && ./RWP.sh
  1. Make the Script WP.sh executable with chmod +x ~/SeasonalWallPapers/WP.sh

*This Script WP.sh is the main source for us hereon-wards.
when ever we add or delete any changes in those 4 folders for the images..we need to run this script to update the .xml files

  1. Run the command to generate required .xml files
    ~/SeasonalWallPapers/WP.sh

Example:

$ ~/SeasonalWallPapers/WP.sh
$ 

*When we run this Script WP.sh it generates the .xml files in each folder with updated wallpapers named FWP.xml, RWP.xml, SWP.xml & WWP.xml

now we need to set any of these four .xml files as per our need.

  1. gsettings set org.gnome.desktop.background picture-uri 'file:///home/user-name/SeasonalWallPapers/Fall/FWP.xml' #change the user-name with yours.

Example:

$ gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Fall/FWP.xml'
$ 

now when ever you want, you can set the required wallpapers with below commands

gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Fall/FWP.xml'

gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Winter/WWP.xml'

gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Spring/RWP.xml'

gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Summer/SWP.xml'

enter image description here

enter image description here

enter image description here

enter image description here

If you still think to automate this which comes every 3months..
create a cron job as per your need with the following example commands.

0 0 1 12 * root gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Fall/FWP.xml'
0 0 1 6 * root gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Winter/WWP.xml'
0 0 1 9 * root gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Spring/RWP.xml'
0 0 1 3 * root gsettings set org.gnome.desktop.background picture-uri 'file:///home/pratap/SeasonalWallPapers/Summer/SWP.xml'
0

Ok. My two cents here for those on Ubuntu 18+ (not sure about previous versions so this is a disclaimer).

In Ubuntu it is possible to make a custom XML-file containing paths to your images with a "duration" and a section with a starting time. For instance:

<background>
  <starttime>
    <year>2000</year>
    <month>3</month>
    <day>21</day>
    <hour>00</hour>
    <minute>00</minute>
    <second>00</second>
  </starttime>
<static>
  <duration>30.00</duration>
  <file>/home/martin/Pictures/Slideshow/spring.jpg</file>
</static>
<static>
  <duration>30.00</duration>
  <file>/home/martin/Pictures/Slideshow/summer.jpg</file>
</static>
</background>

In this example the duration is 30 seconds and the start date/time is march 21st, 2000. Simply add more pictures with the right duration... so calculate the number of seconds from march 21st until june 21st and put this number in the first <duration> part. Then do the same for june 21st until september 21st and put it in the second. Etcetera for the fall and winter.

2
  • I think this answers the question of how to create a slideshow. The original intent of the question was how to change the directory of the slideshow each season. To emphasize the difference, if I decided to add 10 more pictures to the Spring directory, I would have to come back to the XML file and add those in. Or, how would I rotate through those 10 images during the spring? Mar 21, 2023 at 16:18
  • The XML now uses one setting (30 seconds) for each file. One could change the duration to e.g. change it according to each folder (if the images for the 'spring' are distinguishable e.g. in a separate folder). I have a script available that can generate the XML file according to a list of files. askubuntu.com/questions/1278224/… Maybe with some small adaptations one could use this solution. If you're interested I could post it as a new answer including the changes per season
    – Pianoman
    Mar 21, 2023 at 17:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .