├── .gitignore ├── LICENSE ├── README.md ├── diplo_and_friends.py ├── goodreads_to_md_list.py ├── hn500-to-simplepush.py ├── ideas.md ├── music-to-external-hdd.sh └── music-to-subfolders.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Aleksandar Todorović (r3bl) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # automation-scripts 2 | 3 | This is a list of scripts that I use to automate my home. It currently contains the following scripts: 4 | 5 | * [diplo_and_friends.py](#diplo_and_friendspy) 6 | * [goodreads_to_md_list.py](#goodreads_to_md_listpy) 7 | * [hn500-to-simplepush.py](#hn500-to-simplepushpy) 8 | * [music-to-subfolders.sh](#music-to-subfolderssh) 9 | * [music-to-external-hdd.sh](#music-to-external-hddsh) 10 | 11 | The ideas I have in my head are listed in the `ideas.md` file and may or may not be created. 12 | 13 | ## `diplo_and_friends.py` 14 | 15 | Automatically download the latest Diplo & Friends BBC radio show by setting up a cronjob to run this script every Sunday morning. Can easily be modified to automatically download any of the BBC shows. The script tries to download every episode available from the show, but `get_iplayer` is smart enough not to download those that have already been downloaded, therefore avoiding the duplicate downloads. 16 | 17 | **Bonus points:** this script is executed on my [Nextcloud](https://nextcloud.com/) server, so there's a `php occ files:scan` command that re-scans the files in the directory the `.mp3` files are placed in. This script is also integrated with [Simplepush](https://simplepush.io/), so that I would get an Android notification that the new episode is currently being downloaded on my server. 18 | 19 | * **Scripting language:** Python 2 20 | * **Prerequisites:** `pip install requests bs4` and [`get_iplayer`](https://github.com/get-iplayer/get_iplayer). [Nextcloud](https://nextcloud.com/) and [Simplepush](https://simplepush.io/) for bonus points. 21 | 22 | ## `goodreads_to_md_list.py` 23 | 24 | This script works with the Goodreads API. It fetches the list of books from a public Goodreads shelf, and then outputs the list as a Markdown file. The point of this list is to have it synced in some external file, which could later be backed up (by using Git, as you can [see here](https://github.com/aleksandar-todorovic/notes/blob/master/00_books.md)). 25 | 26 | Note that each book in your year needs to have a valid `read_at` field filled out for the lines 53-65 to work. I could have added a small try/except to fix this, but I specifically wanted it to make sure that every book has a `read_at` field filled out before continuing. 27 | 28 | * **Scripting language:** Python 3 29 | * **Prerequisites:** `pip install requests` 30 | 31 | ## `hn500-to-simplepush.py` 32 | 33 | Send a [Simplepush](https://simplepush.io/) notification to your Android device every time a story gets over 500 votes on Hacker News. To use this script, copy it to a device that's constantly online, create a short cronjob for it (something like every five minutes) and modify the script with your Simplepush six-character ID. This script is my re-creation of [Pushbullet's Hacker News 500](https://www.pushbullet.com/channel?tag=newsyc500). 34 | 35 | This script assumes that you have a file called `.hn500-to-simplepush.history` in the same folder as this script. What this file does is it acts like a history of every HN ID that Simplepush sent a notification about. If the HN ID that the script finds is already in the history file, it won't trigger a notification. 36 | 37 | * **Scripting language:** Python3 38 | * **Prerequsites:** `pip install requests` && [Simplepush](https://simplepush.io/). 39 | 40 | ## `music-to-subfolders.sh` 41 | 42 | This script only gets executed if I'm connected to my home WiFi network. It is meant to be executed every X minutes, and what it does is it moves all the music files from my Downloads folder to a specific subfolder in my Music folder. The subfolder gets named using the `-` format, and the script automatically creates that folder in case it no longer exists. 43 | 44 | This script helps me out to keep my Downloads folder cleaner, and makes sure that the Music files are automatically imported to my music player's library. Later on, I can sync these files to an external location, either by using Nextcloud desktop client, or by using `music-to-external-hdd.sh`. 45 | 46 | * **Scripting language:** bash 47 | * **Prerequisites:** N/A 48 | 49 | ## `music-to-external-hdd.sh` 50 | 51 | This script is similar to the one above. It only gets executed when I'm on my home WiFi network, and what it does is it automatically copies just edited subfolders from `music-to-subfolders.sh` into an external hard drive by simply `scp`-ing them to a Raspberry Pi (to which the external hard drive is connected). 52 | 53 | Basically the only reason this script exists and is not a part of the previous one is that I don't want to run the Nextcloud client on my Raspberry Pi, but I am leaving that as an option later on. 54 | 55 | * **Scripting language:** bash 56 | * **Prerequisites:** N/A 57 | -------------------------------------------------------------------------------- /diplo_and_friends.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import requests 3 | import sys, os 4 | from bs4 import BeautifulSoup 5 | 6 | # Simplepush API key. You can get one by installing the app from https://simplepush.io/. 7 | simple_push_key = "{{ SIX CHARACTER CONSUMER KEY GOES HERE}}" 8 | 9 | # Change the URL if you want to download episodes of some other BBC show 10 | r = requests.get('http://www.bbc.co.uk/programmes/b01dmw90/episodes/player') 11 | soup = BeautifulSoup(r.text, 'html.parser') 12 | 13 | mydivs = soup.findAll("div", { "class" : "programme programme--radio programme--episode block-link highlight-box--list br-keyline br-blocklink-page br-page-linkhover-onbg015--hover" }) 14 | 15 | i = 1 16 | for div in mydivs: 17 | name = div.find('span', {'property' : 'name'}) 18 | link = div['data-pid'] 19 | if i == 1: 20 | cmd = "echo 'DOWNLOADING: '" + name.text + "'(Diplo & Friends)'" 21 | os.system(cmd) 22 | print name.text + ': ' + link 23 | # cd into a directory and download the files 24 | cmd = "cd /var/www/data/r3bl/files/Music/Collections/diplo_and_friends && get_iplayer --pid=%s"%(link) 25 | os.system(cmd) 26 | if i == 1: 27 | cmd2 = "curl --data 'key=" + simple_push_key + "&title=" + name.text + "&msg=" + "Downloaded:" + name.text + "(Diplo & Friends)" + "' https://api.simplepush.io/send" 28 | os.system(cmd2) 29 | i = i + 1 30 | # Do a re-scan of that folder so that they become available on Nextcloud 31 | cmd3 = "cd /var/www/html && sudo -u www-data php occ files:scan --path='/r3bl/files/Music/Collections/diplo_and_friends'" 32 | os.system(cmd3) 33 | -------------------------------------------------------------------------------- /goodreads_to_md_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import requests 4 | import xml.etree.ElementTree as ET 5 | 6 | # URL that needs to be GET 7 | url = "https://www.goodreads.com/review/list?v=2" 8 | 9 | # params that should go with the URL 10 | parameters = { 11 | "id" : "37688006-aleksandar-todorovi", 12 | "shelf" : "read", 13 | "sort" : "date_read", 14 | "order" : "a", 15 | "per_page" : 200, 16 | "key" : "jtHlppFX53E4ybfdovbA" 17 | } 18 | 19 | # make a GET request 20 | r = requests.get(url, params=parameters) 21 | 22 | # parse XMl 23 | root = ET.fromstring(r.text) 24 | 25 | # XML Structure: 26 | # 27 | # 28 | # 29 | # 30 | # XXXXXXXXXXXXtitle 32 | # 33 | # 34 | # Jon Doe 35 | # 36 | # 37 | # 38 | # 39 | # 5 40 | # 41 | # 42 | # 43 | # 44 | f = open('00_books.md', 'w') 45 | 46 | f.write("# Books\n\n> After all any book is just a list of thoughts of another guy, who might be wrong.\n\nThis file is the exported version of my [Goodreads `read` shelf](https://www.goodreads.com/review/list/37688006-aleksandar-todorovi?shelf=read), synced using my [`goodreads_to_md_list.py`](https://github.com/aleksandar-todorovic/automation-scripts#goodreads_to_md_listpy) script. Having a Git backup prevents me from feeling that I might be vendor-locked-in, even though it's just a freaking list of books that I could probably re-create.\n\nThe books below are in order of me marking them as read on Goodreads, from oldest to newest. The stars are my subjective opinion of the book on the scale from one to five.\n\nFormat: ``* `author_name` book_title (rating) [[isbn13](link_to_goodreads)]``\n\n") 47 | 48 | # Set reading goals to zero 49 | goal_2015 = 0 50 | goal_2016 = 0 51 | goal_2017 = 0 52 | 53 | for reviews in root.find('reviews'): 54 | read_at = reviews.find('read_at').text 55 | # Final four characters represent a year 56 | year = read_at[-4:] 57 | if int(year) == 2015: 58 | goal_2015 = goal_2015 + 1 59 | elif int(year) == 2016: 60 | goal_2016 = goal_2016 + 1 61 | elif int(year) == 2017: 62 | goal_2017 = goal_2017 + 1 63 | 64 | # Print down the reading goals 65 | f.write("## Reading Goals:\n\n* 2015: " + str(goal_2015) + "/25\n* 2016: " + str(goal_2016) + "/20\n* 2017: " + str(goal_2017) + "/25\n\n## Books I have read\n\n") 66 | 67 | for review in root.find('reviews'): 68 | book = review.find('book') 69 | title = book.find('title_without_series').text 70 | authors = book.find('authors') 71 | author = authors.find('author') 72 | name = author.find('name').text 73 | stars_int = review.find('rating').text 74 | stars_str = "" 75 | i = 0 76 | while i < 5: 77 | if i < int(stars_int): 78 | stars_str = stars_str + "★" 79 | elif i == int(stars_int) or i > int(stars_int): 80 | stars_str = stars_str + "☆" 81 | i = i + 1 82 | isbn = book.find('isbn13').text 83 | link = book.find('link').text 84 | f.write("* `" + name + "` " + title + " (" + stars_str + ") [[" + str(isbn) + "](" + link + ")]\n") 85 | 86 | f.close() 87 | -------------------------------------------------------------------------------- /hn500-to-simplepush.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import requests 4 | import json 5 | import sys, os 6 | from simplepush import send 7 | 8 | #TODO: Speed this script up. It currently takes ~28 seconds to finish. 9 | 10 | # Fetches the IDs of top HN stories at the moment. 11 | r = requests.get('https://hacker-news.firebaseio.com/v0/topstories.json') 12 | 13 | simplepush_id = "{{ SIX CHARACTER SIMPLEPUSH ID HERE }}" 14 | hn_id = "" 15 | i = 0 16 | score = 0 17 | 18 | # Fetches the details from the first 30 story IDs (since the HN homepage contains 30 stories). 19 | while i < 30: 20 | hn_id = json.loads(r.text)[i] 21 | r2 = requests.get('https://hacker-news.firebaseio.com/v0/item/' + str(hn_id) + '.json?print=pretty') 22 | # Gets the score of the ID 23 | score = json.loads(r2.text)['score'] 24 | # Checks if the score is bigger than 500 and proceeds if it is. 25 | if score > 500: 26 | print ("\nHN ID: " + str(hn_id)) 27 | # Open the history file 28 | with open(".hn-to-simplepush.history", "r+") as history_file: 29 | # Checks if the ID is already in the notification history. 30 | line_found = any(str(hn_id) in line for line in history_file) 31 | print("line_found = " + str(line_found)) 32 | if not line_found: 33 | # Append the ID to a file so that this ID wouldn't trigger notifications over and over again every time you run the script. 34 | history_file.write(str(hn_id) + "\n") 35 | # Send a Simplepush notification 36 | send(simplepush_id, json.loads(r2.text)['title'], json.loads(r2.text)['url']) 37 | i = i + 1 38 | -------------------------------------------------------------------------------- /ideas.md: -------------------------------------------------------------------------------- 1 | # Ideas 2 | 3 | * [ ] Automatic book transfer (calibre on elementary/Windows -> Android) 4 | * [ ] Automatic music transfer (music from the `dnlds` to Android) 5 | * [ ] Downloaded movies to an external HDD connected to a Pi (?) 6 | * [ ] PulseAudio server on a Pi 7 | * [ ] Thunderbird installation script that will automatically download Thunderbid and apply the [`montreail`](https://github.com/spymastermatt/thunderbird-monterail) theme out of the box. 8 | -------------------------------------------------------------------------------- /music-to-external-hdd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$(nmcli -t -f name con show --active | grep '')" = '' ]; then 4 | echo "Connected to the home network. Proceeding..." 5 | current_date=$(date +%Y-%m) 6 | scp -r ~/music/$current_date pi@192.168.X.X:/media/XXXX/music/$current_date 7 | fi 8 | -------------------------------------------------------------------------------- /music-to-subfolders.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | current_date=$(date +%Y-%m) 4 | mkdir -p ~/music/$current_date 5 | 6 | cd ~/dnlds 7 | mv *.mp3 *.wav *.flac *.m4a ~/music/$current_date 8 | --------------------------------------------------------------------------------