Compare commits
2 commits
6c1ca37fd3
...
00872dfed2
Author | SHA1 | Date | |
---|---|---|---|
coderkun | 00872dfed2 | ||
coderkun | e197a579ed |
225
clean-tags.py
225
clean-tags.py
|
@ -1,225 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
# Dependencies:
|
|
||||||
# – python-mutagen
|
|
||||||
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
|
|
||||||
from mutagen.id3 import ID3
|
|
||||||
from mutagen.flac import FLAC
|
|
||||||
from mutagen import MutagenError
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Styling:
|
|
||||||
"""Output styling constants."""
|
|
||||||
ENDC = '\x1b[0m'
|
|
||||||
BOLD = '\x1b[1m'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TagCleaner:
|
|
||||||
"""
|
|
||||||
Class to check audio files for unwanted tags and provide routines to clean
|
|
||||||
them.
|
|
||||||
"""
|
|
||||||
INDENTATION = " "
|
|
||||||
FILE_EXTENSIONS = ['.mp3', '.flac', '.ogg']
|
|
||||||
TAGS_ID3 = ['TALB', 'TDRC', 'TIT2', 'TPE1', 'TRCK']
|
|
||||||
TAGS_VORBIS_COMMENTS = ['ALBUM', 'ARTIST', 'DATE', 'TITLE', 'TRACKNUMBER']
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, folder):
|
|
||||||
"""Construct a new tag cleaner instancce."""
|
|
||||||
self._logger = logging.getLogger(__class__.__name__)
|
|
||||||
self._dry = False
|
|
||||||
self._id3 = True
|
|
||||||
self._flac = True
|
|
||||||
self._folder = folder
|
|
||||||
self._files = []
|
|
||||||
self._read_files(folder)
|
|
||||||
|
|
||||||
|
|
||||||
def set_dry(self, dry):
|
|
||||||
"""Set dry mode (do not save any file)."""
|
|
||||||
self._dry = dry
|
|
||||||
|
|
||||||
|
|
||||||
def set_id3(self, do):
|
|
||||||
"""Set whether to clean ID3 tags or not."""
|
|
||||||
self._id3 = do
|
|
||||||
|
|
||||||
|
|
||||||
def set_flac(self, do):
|
|
||||||
"""Set whether to clean FLAC vorbis comments or not."""
|
|
||||||
self._flac = do
|
|
||||||
|
|
||||||
|
|
||||||
def clean_files(self):
|
|
||||||
"""Clean all found files."""
|
|
||||||
self._logger.info("Clean files")
|
|
||||||
for filename in self._files:
|
|
||||||
self._clean_file(filename)
|
|
||||||
|
|
||||||
|
|
||||||
def _read_files(self, folder):
|
|
||||||
self._logger.info("Read files from \"{}\"".format(folder))
|
|
||||||
for dirname, dirnames, filenames in os.walk(folder):
|
|
||||||
for filename in filenames:
|
|
||||||
if filename.startswith("."):
|
|
||||||
continue
|
|
||||||
(name, ext) = os.path.splitext(filename)
|
|
||||||
if ext.lower() not in TagCleaner.FILE_EXTENSIONS:
|
|
||||||
continue
|
|
||||||
self._logger.debug("Found file \"%s\"", os.path.join(dirname, filename))
|
|
||||||
self._files.append(os.path.join(dirname, filename))
|
|
||||||
self._logger.info("Found %d files", len(self._files))
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_file(self, filename):
|
|
||||||
"""Clean a file."""
|
|
||||||
self._logger.info("Clean file \"%s\"", filename)
|
|
||||||
if os.path.isfile(filename):
|
|
||||||
# ID3
|
|
||||||
if self._id3:
|
|
||||||
self._clean_id3(filename)
|
|
||||||
# FLAC
|
|
||||||
if self._flac:
|
|
||||||
self._clean_flac(filename)
|
|
||||||
else:
|
|
||||||
self._logger.info("Not a file: \"%s\"", filename)
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_id3(self, filename):
|
|
||||||
"""Clean ID3 tags."""
|
|
||||||
self._logger.info("Clean ID3")
|
|
||||||
try:
|
|
||||||
tags = ID3(filename)
|
|
||||||
print(Styling.BOLD + filename[len(self._folder):] + Styling.ENDC)
|
|
||||||
print("ID3", "v{}.{}.{}".format(*tags.version))
|
|
||||||
valid = True
|
|
||||||
|
|
||||||
# Check version
|
|
||||||
if tags.version != (2, 4, 0):
|
|
||||||
valid = False
|
|
||||||
|
|
||||||
# Unknown tags
|
|
||||||
if tags.unknown_frames:
|
|
||||||
valid = False
|
|
||||||
print("Unknown frames:")
|
|
||||||
for frame in tags.unknown_frames:
|
|
||||||
print(frame)
|
|
||||||
|
|
||||||
# Invalid tags
|
|
||||||
invalid_tags = []
|
|
||||||
for tag in tags:
|
|
||||||
if len(tag) > 4:
|
|
||||||
tag = tag[0:4]
|
|
||||||
if tag not in TagCleaner.TAGS_ID3:
|
|
||||||
invalid_tags.append(tag)
|
|
||||||
if invalid_tags:
|
|
||||||
valid = False
|
|
||||||
print("Unwanted tags:")
|
|
||||||
for tag in invalid_tags:
|
|
||||||
for frame in tags.getall(tag):
|
|
||||||
if hasattr(frame, 'text'):
|
|
||||||
for value in frame.text:
|
|
||||||
print("{}{}: {}".format(TagCleaner.INDENTATION, tag, value))
|
|
||||||
else:
|
|
||||||
print("{}{}:".format(TagCleaner.INDENTATION, tag), frame)
|
|
||||||
|
|
||||||
# Save
|
|
||||||
if not valid:
|
|
||||||
# Delete tags
|
|
||||||
for tag in invalid_tags:
|
|
||||||
print("Delete", tag)
|
|
||||||
tags.delall(tag)
|
|
||||||
|
|
||||||
# Save file
|
|
||||||
if not self._dry:
|
|
||||||
try:
|
|
||||||
tags.save()
|
|
||||||
print("File saved")
|
|
||||||
except Exception as e:
|
|
||||||
self._logger.error("Saving of file \"%s\" failed: %s", filename, e)
|
|
||||||
else:
|
|
||||||
print("File not saved (running in dry mode)")
|
|
||||||
else:
|
|
||||||
self._logger.info("Clean, nothing to do")
|
|
||||||
except MutagenError as e:
|
|
||||||
self._logger.info("Cleaning of ID3 tags failed: %s", e)
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_flac(self, filename):
|
|
||||||
"""Clean FLAC vorbis comments."""
|
|
||||||
self._logger.info("Clean FLAC vorbis comments")
|
|
||||||
try:
|
|
||||||
flac = FLAC(filename)
|
|
||||||
invalid_comments = {}
|
|
||||||
if flac.tags:
|
|
||||||
invalid_comments = self._clean_vorbis_comments(flac.tags)
|
|
||||||
# Delete comments
|
|
||||||
if invalid_comments:
|
|
||||||
for key in invalid_comments.keys():
|
|
||||||
print("Delete", key)
|
|
||||||
del flac.tags[key]
|
|
||||||
if not self._dry:
|
|
||||||
flac.save()
|
|
||||||
print("File saved")
|
|
||||||
else:
|
|
||||||
print("File not saved (running in dry mode)")
|
|
||||||
else:
|
|
||||||
self._logger.info("Clean, nothing to do")
|
|
||||||
except MutagenError as e:
|
|
||||||
self._logger.info("Cleaning of FLAC vorbis comments failed: %s", e)
|
|
||||||
|
|
||||||
|
|
||||||
def _clean_vorbis_comments(self, comments):
|
|
||||||
invalid_comments = {}
|
|
||||||
for key, value in comments:
|
|
||||||
if key not in TagCleaner.TAGS_VORBIS_COMMENTS:
|
|
||||||
invalid_comments[key] = value
|
|
||||||
if invalid_comments:
|
|
||||||
print("Unwanted comments:")
|
|
||||||
for key in invalid_comments.keys():
|
|
||||||
print("{}{}: {}".format(TagCleaner.INDENTATION, key, invalid_comments[key]))
|
|
||||||
|
|
||||||
return invalid_comments
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Setup command line
|
|
||||||
parser = argparse.ArgumentParser("Clean unwanted tags from audio files to keep your music library clean.")
|
|
||||||
parser.add_argument('-d', '--dry', dest='dry', action='store_true', default=False, help="dry run, do not modify any file, just print information")
|
|
||||||
parser.add_argument('-v', '--verbose', dest='verbosity', action='count', default=0, help="be verbose, show more information")
|
|
||||||
parser.add_argument('-l', '--logfile', dest='logfile', help="specify name of logfile")
|
|
||||||
parser.add_argument('--no-id3', dest='id3', action='store_false', help="disable cleaning of ID3 tags")
|
|
||||||
parser.add_argument('--no-fac', dest='flac', action='store_false', help="disable cleaning of FLAC vorbis comments")
|
|
||||||
parser.add_argument('folder', help="source folder to read audio files from")
|
|
||||||
parser.set_defaults(id3=True, flac=True)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Setup logging
|
|
||||||
logging.basicConfig(
|
|
||||||
filename=args.logfile,
|
|
||||||
level=logging.ERROR-(10*args.verbosity),
|
|
||||||
format="%(asctime)s %(levelname)s: %(message)s"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create tag cleaner instance
|
|
||||||
tag_cleaner = TagCleaner(args.folder)
|
|
||||||
tag_cleaner.set_dry(args.dry)
|
|
||||||
tag_cleaner.set_id3(args.id3)
|
|
||||||
tag_cleaner.set_flac(args.flac)
|
|
||||||
|
|
||||||
# Run action
|
|
||||||
tag_cleaner.clean_files()
|
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Count the number of unread emails and return the count in the i3/sway bar
|
|
||||||
# format.
|
|
||||||
|
|
||||||
# Settings
|
|
||||||
MAILDIRNEW="$HOME/Dokumente/eMails/*/INBOX/new/"
|
|
||||||
|
|
||||||
# Count new mails
|
|
||||||
MAILNEW="$(find $MAILDIRNEW -type f | wc -l)"
|
|
||||||
|
|
||||||
# Print count in i3/sway bar format
|
|
||||||
echo $MAILNEW
|
|
||||||
echo $MAILNEW
|
|
||||||
[ ${MAILNEW} -ge 1 ] && exit 33
|
|
||||||
|
|
||||||
exit 0
|
|
28
pa.bash
28
pa.bash
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
|
|
||||||
# Detect current profile
|
|
||||||
function profile {
|
|
||||||
CURRENT_PROFILE=$(LC_ALL=C pactl list sinks | grep -i "active port" | cut -d " " -f 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# If either i3’s button is 1 or the first argument is “switch”, switch profile
|
|
||||||
if [[ $BLOCK_BUTTON -eq 1 ]] || [ "$1" == "switch" ] ; then
|
|
||||||
profile
|
|
||||||
if ! [[ "$CURRENT_PROFILE" == *"iec958"* ]] ; then
|
|
||||||
pacmd set-card-profile 0 output:iec958-stereo
|
|
||||||
else
|
|
||||||
pacmd set-card-profile 0 output:hdmi-stereo
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Print out current profile
|
|
||||||
profile
|
|
||||||
if [[ "$CURRENT_PROFILE" == *"iec958"* ]] ; then
|
|
||||||
echo "digital"
|
|
||||||
elif [[ "$CURRENT_PROFILE" == *"hdmi"* ]] ; then
|
|
||||||
echo "hdmi"
|
|
||||||
else
|
|
||||||
echo "${CURRENT_PROFILE%%-*}"
|
|
||||||
fi
|
|
28
pa.sh
28
pa.sh
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
|
|
||||||
# Detect current profile
|
|
||||||
profile() {
|
|
||||||
CURRENT_PROFILE=$(LC_ALL=C pactl list sinks | grep -i "active port" | cut -d " " -f 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# If either i3’s button is 1 or the first argument is “switch”, switch profile
|
|
||||||
if [[ $BLOCK_BUTTON -eq 1 ]] || [ "$1" == "switch" ] ; then
|
|
||||||
profile
|
|
||||||
if ! [[ "$CURRENT_PROFILE" == *"iec958"* ]] ; then
|
|
||||||
pacmd set-card-profile 0 output:iec958-stereo
|
|
||||||
else
|
|
||||||
pacmd set-card-profile 0 output:hdmi-stereo
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Print out current profile
|
|
||||||
profile
|
|
||||||
if [[ "$CURRENT_PROFILE" == *"iec958"* ]] ; then
|
|
||||||
echo "digital"
|
|
||||||
elif [[ "$CURRENT_PROFILE" == *"hdmi"* ]] ; then
|
|
||||||
echo "hdmi"
|
|
||||||
else
|
|
||||||
echo "${CURRENT_PROFILE%%-*}"
|
|
||||||
fi
|
|
17
passmenu
17
passmenu
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
shopt -s nullglob globstar
|
|
||||||
|
|
||||||
# Present menu to select password
|
|
||||||
prefix=${PASSWORD_STORE_DIR-~/.password-store}
|
|
||||||
password_files=( "$prefix"/**/*.gpg )
|
|
||||||
password_files=( "${password_files[@]#"$prefix"/}" )
|
|
||||||
password_files=( "${password_files[@]%.gpg}" )
|
|
||||||
password=$(printf '%s\n' "${password_files[@]}" | bemenu $@)
|
|
||||||
|
|
||||||
# Copy password to clipboard
|
|
||||||
pass show -c "$password" 2>/dev/null
|
|
||||||
|
|
||||||
# Send notification
|
|
||||||
notify-send -u critical -t 45000 "Password in clipboard" \
|
|
||||||
"The password for \"$password\" is currently in the clipboard."
|
|
17
passusermenu
17
passusermenu
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
shopt -s nullglob globstar
|
|
||||||
|
|
||||||
# Present menu to select password
|
|
||||||
prefix=${PASSWORD_STORE_DIR-~/.password-store}
|
|
||||||
password_files=( "$prefix"/**/*.gpg )
|
|
||||||
password_files=( "${password_files[@]#"$prefix"/}" )
|
|
||||||
password_files=( "${password_files[@]%.gpg}" )
|
|
||||||
password=$(printf '%s\n' "${password_files[@]}" | bemenu $@)
|
|
||||||
|
|
||||||
# Copy password to clipboard
|
|
||||||
pass user "$password" 2>/dev/null
|
|
||||||
|
|
||||||
# Send notification
|
|
||||||
notify-send -u critical -t 45000 "Username in clipboard" \
|
|
||||||
"The username for \"$password\" is currently in the clipboard."
|
|
13
timewmenu
Executable file
13
timewmenu
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
|
# Present menu to select tag
|
||||||
|
tag=$(timew tags | tail +4 | cut -d " " -f 1 | bemenu $@)
|
||||||
|
tag=$(echo "${tag%-*}" | xargs echo -n)
|
||||||
|
|
||||||
|
# Start timetracking
|
||||||
|
output=$(timew start "$tag")
|
||||||
|
|
||||||
|
# Send notification
|
||||||
|
notify-send -t 5000 "timew" "${output}"
|
Loading…
Reference in a new issue