mirror of
https://github.com/cooperhammond/irs.git
synced 2025-04-17 14:01:39 +00:00
Post-Processors are reimplemented. Call them with -o and -l flags.
This commit is contained in:
parent
fb09be845d
commit
5f1068e645
|
@ -15,4 +15,5 @@ install:
|
||||||
script:
|
script:
|
||||||
- python tests/song.py
|
- python tests/song.py
|
||||||
- python tests/album.py
|
- python tests/album.py
|
||||||
- python tests/playlist.py
|
- python tests/playlist.py
|
||||||
|
- python tests/post_processors.py
|
|
@ -1,4 +1,6 @@
|
||||||
<div style="text-align:center"><img src ="http://i.imgur.com/VbsyTe7.png" /></div>
|
<div align="center">
|
||||||
|
<img src ="http://i.imgur.com/VbsyTe7.png" />
|
||||||
|
</div>
|
||||||
Ironic Redistribution System
|
Ironic Redistribution System
|
||||||
===
|
===
|
||||||
[](http://www.gnu.org/licenses/gpl.html)
|
[](http://www.gnu.org/licenses/gpl.html)
|
||||||
|
@ -32,6 +34,9 @@ optional arguments:
|
||||||
Specify username. Must be used with -p/--playlist
|
Specify username. Must be used with -p/--playlist
|
||||||
-p PLAYLIST, --playlist PLAYLIST
|
-p PLAYLIST, --playlist PLAYLIST
|
||||||
Specify playlist name. Must be used with -u/--username
|
Specify playlist name. Must be used with -u/--username
|
||||||
|
-l LOCATION, --location LOCATION
|
||||||
|
Specify a directory to place files in.
|
||||||
|
-o, --organize Organize downloaded files.
|
||||||
```
|
```
|
||||||
So all of these are valid commands:
|
So all of these are valid commands:
|
||||||
```
|
```
|
||||||
|
|
26
irs/cli.py
26
irs/cli.py
|
@ -7,26 +7,44 @@ import os
|
||||||
|
|
||||||
# Powered by:
|
# Powered by:
|
||||||
from .ripper import Ripper
|
from .ripper import Ripper
|
||||||
from .utils import console
|
from .utils import console, remove_none_values
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
# Single Song
|
||||||
parser.add_argument("-a", "--artist", dest="artist", help="Specify artist name. Must be used with -s/--song")
|
parser.add_argument("-a", "--artist", dest="artist", help="Specify artist name. Must be used with -s/--song")
|
||||||
parser.add_argument("-s", "--song", dest="song", help="Specify song name. Must be used with -a/--artist")
|
parser.add_argument("-s", "--song", dest="song", help="Specify song name. Must be used with -a/--artist")
|
||||||
|
|
||||||
|
# Album
|
||||||
parser.add_argument("-A", "--album", dest="album", help="Specify album name")
|
parser.add_argument("-A", "--album", dest="album", help="Specify album name")
|
||||||
|
|
||||||
|
# Playlist
|
||||||
parser.add_argument("-u", "--username", dest="username", help="Specify username. Must be used with -p/--playlist")
|
parser.add_argument("-u", "--username", dest="username", help="Specify username. Must be used with -p/--playlist")
|
||||||
parser.add_argument("-p", "--playlist", dest="playlist", help="Specify playlist name. Must be used with -u/--username")
|
parser.add_argument("-p", "--playlist", dest="playlist", help="Specify playlist name. Must be used with -u/--username")
|
||||||
|
|
||||||
|
# Post-Processors
|
||||||
|
parser.add_argument("-l", "--location", dest="location", help="Specify a directory to place files in.")
|
||||||
|
parser.add_argument("-o", "--organize", dest="organize", action="store_true", help="Organize downloaded files.")
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
ripper_args = {
|
||||||
|
"post_processors": {
|
||||||
|
"location": args.location,
|
||||||
|
"organize": args.organize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ripper = Ripper(ripper_args)
|
||||||
|
|
||||||
if args.artist and args.song:
|
if args.artist and args.song:
|
||||||
Ripper().song(args.song, args.artist)
|
ripper.song(args.song, args.artist)
|
||||||
elif args.album:
|
elif args.album:
|
||||||
Ripper().spotify_list("album", args.album)
|
ripper.spotify_list("album", args.album)
|
||||||
elif args.username and args.playlist:
|
elif args.username and args.playlist:
|
||||||
Ripper().spotify_list("playlist", args.playlist, args.username)
|
ripper.spotify_list("playlist", args.playlist, args.username)
|
||||||
else:
|
else:
|
||||||
console(Ripper())
|
console(Ripper())
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# MP3 Metadata editing
|
# MP3 Metadata editing
|
||||||
from mutagen.mp3 import MP3, EasyMP3
|
from mutagen.mp3 import MP3, EasyMP3
|
||||||
from mutagen.easyid3 import EasyID3
|
from mutagen.easyid3 import EasyID3, EasyID3KeyError
|
||||||
from mutagen.id3 import * # There's A LOT of stuff to import, forgive me.
|
from mutagen.id3 import * # There's A LOT of stuff to import, forgive me.
|
||||||
from mutagen.id3 import APIC
|
from mutagen.id3 import APIC
|
||||||
|
|
||||||
|
@ -37,7 +37,13 @@ class Metadata:
|
||||||
def add_tag(self, tag, data):
|
def add_tag(self, tag, data):
|
||||||
# For valid tags: `EasyID3.valid_keys.keys()`
|
# For valid tags: `EasyID3.valid_keys.keys()`
|
||||||
self.mp3[tag] = data
|
self.mp3[tag] = data
|
||||||
self.mp3.save()
|
self.mp3.save()
|
||||||
|
|
||||||
|
def read_tag(self, tag):
|
||||||
|
try:
|
||||||
|
return self.mp3[tag]
|
||||||
|
except EasyID3KeyError:
|
||||||
|
return []
|
||||||
|
|
||||||
def add_album_art(self, image_url):
|
def add_album_art(self, image_url):
|
||||||
mp3 = EasyMP3(self.location, ID3=ID3)
|
mp3 = EasyMP3(self.location, ID3=ID3)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class Ripper:
|
||||||
def __init__(self, args={}):
|
def __init__(self, args={}):
|
||||||
self.args = args
|
self.args = args
|
||||||
self.locations = []
|
self.locations = []
|
||||||
|
self.type = None
|
||||||
try:
|
try:
|
||||||
client_credentials_manager = SpotifyClientCredentials(os.environ["SPOTIFY_CLIENT_ID"], os.environ["SPOTIFY_CLIENT_SECRET"])
|
client_credentials_manager = SpotifyClientCredentials(os.environ["SPOTIFY_CLIENT_ID"], os.environ["SPOTIFY_CLIENT_SECRET"])
|
||||||
self.spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
self.spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
|
@ -36,6 +37,52 @@ class Ripper:
|
||||||
self.spotify = spotipy.Spotify()
|
self.spotify = spotipy.Spotify()
|
||||||
self.authorized = False
|
self.authorized = False
|
||||||
|
|
||||||
|
def post_processing(self, locations):
|
||||||
|
post_processors = self.args.get("post_processors")
|
||||||
|
if post_processors:
|
||||||
|
if type(post_processors.get("location")) is str:
|
||||||
|
for index, loc in enumerate(locations):
|
||||||
|
new_file_name = post_processors["location"] + "/" + loc
|
||||||
|
os.rename(loc, new_file_name)
|
||||||
|
locations[index] = new_file_name
|
||||||
|
if post_processors.get("organize") == True:
|
||||||
|
if self.type == "album":
|
||||||
|
for index, loc in enumerate(locations):
|
||||||
|
mp3 = Metadata(loc)
|
||||||
|
new_loc = ""
|
||||||
|
if len(loc.split("/")) > 1:
|
||||||
|
new_loc = "/".join(loc.split("/")[0:-1])
|
||||||
|
file_name = loc.split("/")[-1]
|
||||||
|
else:
|
||||||
|
file_name = loc
|
||||||
|
artist, album = mp3.read_tag("artist")[0], mp3.read_tag("album")
|
||||||
|
new_loc += blank(artist, False)
|
||||||
|
if album != []:
|
||||||
|
new_loc += "/" + blank(album[0], False)
|
||||||
|
if not os.path.exists(new_loc):
|
||||||
|
os.makedirs(new_loc)
|
||||||
|
new_loc += "/" + file_name
|
||||||
|
loc = loc.replace("//", "/")
|
||||||
|
new_loc = new_loc.replace("//", "/")
|
||||||
|
os.rename(loc, new_loc)
|
||||||
|
locations[index] = new_loc
|
||||||
|
elif self.type == "playlist":
|
||||||
|
for index, loc in enumerate(locations):
|
||||||
|
new_loc = ""
|
||||||
|
if len(loc.split("/")) > 1:
|
||||||
|
new_loc = "/".join(loc.split("/")[0:-1])
|
||||||
|
file_name = loc.split("/")[-1]
|
||||||
|
else:
|
||||||
|
file_name = loc
|
||||||
|
new_loc += blank(self.playlist_title, False)
|
||||||
|
if not os.path.exists(new_loc):
|
||||||
|
os.makedirs(new_loc)
|
||||||
|
loc = loc.replace("//", "/")
|
||||||
|
new_loc = (new_loc + "/" + file_name).replace("//", "/")
|
||||||
|
os.rename(loc, new_loc)
|
||||||
|
|
||||||
|
return locations
|
||||||
|
|
||||||
def find_yt_url(self, song=None, artist=None, additional_search="lyrics"):
|
def find_yt_url(self, song=None, artist=None, additional_search="lyrics"):
|
||||||
try:
|
try:
|
||||||
if not song: song = self.args["song_title"]
|
if not song: song = self.args["song_title"]
|
||||||
|
@ -87,6 +134,12 @@ class Ripper:
|
||||||
self.code = results[0]
|
self.code = results[0]
|
||||||
|
|
||||||
return ("https://youtube.com" + self.code["href"], self.code["title"])
|
return ("https://youtube.com" + self.code["href"], self.code["title"])
|
||||||
|
|
||||||
|
def album(self, title): # Alias for `spotify_list("album", ...)`
|
||||||
|
return self.spotify_list("album", title)
|
||||||
|
|
||||||
|
def playlist(self, title, username): # Alias for `spotify_list("playlist", ...)`
|
||||||
|
return self.spotify_list("playlist", title, username)
|
||||||
|
|
||||||
def spotify_list(self, type=None, title=None, username=None):
|
def spotify_list(self, type=None, title=None, username=None):
|
||||||
try:
|
try:
|
||||||
|
@ -96,6 +149,9 @@ class Ripper:
|
||||||
username = self.args["username"]
|
username = self.args["username"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ValueError("Must specify type/title/username in `args` with init, or in method arguments.")
|
raise ValueError("Must specify type/title/username in `args` with init, or in method arguments.")
|
||||||
|
|
||||||
|
if not self.type:
|
||||||
|
self.type = type
|
||||||
|
|
||||||
if type == "album":
|
if type == "album":
|
||||||
search = title
|
search = title
|
||||||
|
@ -138,6 +194,8 @@ class Ripper:
|
||||||
|
|
||||||
for track in the_list["tracks"]["items"]:
|
for track in the_list["tracks"]["items"]:
|
||||||
if type == "playlist":
|
if type == "playlist":
|
||||||
|
self.playlist_title = the_list["name"] # For post-processors
|
||||||
|
|
||||||
file_prefix = str(len(tracks) + 1) + " - "
|
file_prefix = str(len(tracks) + 1) + " - "
|
||||||
track = track["track"]
|
track = track["track"]
|
||||||
album = self.spotify.album(track["album"]["uri"])
|
album = self.spotify.album(track["album"]["uri"])
|
||||||
|
@ -178,7 +236,10 @@ class Ripper:
|
||||||
if loc != False:
|
if loc != False:
|
||||||
#update_download_log_line_status(track, "downloaded")
|
#update_download_log_line_status(track, "downloaded")
|
||||||
locations.append(loc)
|
locations.append(loc)
|
||||||
|
|
||||||
|
if self.type in ("album", "playlist"):
|
||||||
|
return self.post_processing(locations)
|
||||||
|
|
||||||
#os.remove(".irs-download-log")
|
#os.remove(".irs-download-log")
|
||||||
return locations
|
return locations
|
||||||
|
|
||||||
|
@ -201,10 +262,13 @@ class Ripper:
|
||||||
"disc_number": track["disc_number"],
|
"disc_number": track["disc_number"],
|
||||||
|
|
||||||
"compilation": "", # If this method is being called, it's not a compilation
|
"compilation": "", # If this method is being called, it's not a compilation
|
||||||
"file_prefix": "" # And therefore, won't have a prefix
|
"file_prefix": "" # And therefore, won't have a prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
def song(self, song, artist, data={}): # Takes data from `parse_song_data`
|
def song(self, song, artist, data={}): # Takes data from `parse_song_data`
|
||||||
|
if not self.type:
|
||||||
|
self.type = "song"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not song: song = self.args["song_title"]
|
if not song: song = self.args["song_title"]
|
||||||
if not artist: artist = self.args["artist"]
|
if not artist: artist = self.args["artist"]
|
||||||
|
@ -266,5 +330,7 @@ class Ripper:
|
||||||
m.add_tag("compilation", data["compilation"])
|
m.add_tag("compilation", data["compilation"])
|
||||||
m.add_album_art( str(data["album_art"]))
|
m.add_album_art( str(data["album_art"]))
|
||||||
|
|
||||||
|
if self.type == "song":
|
||||||
|
return self.post_processing([file_name])
|
||||||
|
|
||||||
return file_name
|
return file_name
|
13
irs/utils.py
13
irs/utils.py
|
@ -27,7 +27,7 @@ def my_hook(d):
|
||||||
|
|
||||||
|
|
||||||
#=================================
|
#=================================
|
||||||
# String Manipulation and Checking
|
# Object Manipulation and Checking
|
||||||
#=================================
|
#=================================
|
||||||
|
|
||||||
def check_garbage_phrases(phrases, string, title):
|
def check_garbage_phrases(phrases, string, title):
|
||||||
|
@ -70,7 +70,16 @@ def flatten(l):
|
||||||
else:
|
else:
|
||||||
flattened_list.append(x)
|
flattened_list.append(x)
|
||||||
return flattened_list
|
return flattened_list
|
||||||
|
|
||||||
|
def remove_none_values(d):
|
||||||
|
new_d = d
|
||||||
|
for x in list(d.keys()):
|
||||||
|
if type(new_d[x]) is list:
|
||||||
|
new_d[x] = remove_none_values(d[x])
|
||||||
|
elif new_d[x] == None:
|
||||||
|
del new_d[x]
|
||||||
|
return new_d
|
||||||
|
|
||||||
#=========================================
|
#=========================================
|
||||||
# Download Log Reading/Updating/Formatting
|
# Download Log Reading/Updating/Formatting
|
||||||
#=========================================
|
#=========================================
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -2,7 +2,7 @@ from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='irs',
|
name='irs',
|
||||||
version='6.0.1',
|
version='6.1.1',
|
||||||
description='A music downloader that just gets metadata.',
|
description='A music downloader that just gets metadata.',
|
||||||
url='https://github.com/kepoorhampond/irs',
|
url='https://github.com/kepoorhampond/irs',
|
||||||
author='Kepoor Hampond',
|
author='Kepoor Hampond',
|
||||||
|
|
18
tests/post_processors.py
Normal file
18
tests/post_processors.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from irs.ripper import Ripper
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists("test_dir"):
|
||||||
|
os.makedirs("test_dir")
|
||||||
|
Ripper({
|
||||||
|
"post_processors": {
|
||||||
|
"location": "test_dir/",
|
||||||
|
"organize": True,
|
||||||
|
}
|
||||||
|
}).album("Da Frame 2R / Matador")
|
||||||
|
|
||||||
|
Ripper({
|
||||||
|
"post_processors": {
|
||||||
|
"location": "test_dir/",
|
||||||
|
"organize": True,
|
||||||
|
}
|
||||||
|
}).playlist("IRS Testing", "prakkillian")
|
Loading…
Reference in a new issue