mirror of
https://github.com/bspeice/Melodia
synced 2024-12-26 00:28:13 -05:00
Restructure relationship b/w Songs and Archives
Songs now have a ForeignKey to Archive - one song can not be part of many Archives.
This commit is contained in:
parent
0d467e8457
commit
17960be548
@ -1,7 +1,5 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from song import Song
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This is the archive model for the archiving backend of Melodia.
|
This is the archive model for the archiving backend of Melodia.
|
||||||
It's purpose is to control the high-level functionality of managing
|
It's purpose is to control the high-level functionality of managing
|
||||||
@ -31,8 +29,8 @@ class Archive (models.Model):
|
|||||||
#Note that we're not using FilePathField since this is actually a folder
|
#Note that we're not using FilePathField since this is actually a folder
|
||||||
root_folder = models.CharField(max_length = 255)
|
root_folder = models.CharField(max_length = 255)
|
||||||
|
|
||||||
#And a reference to the songs in this archive
|
#We've removed the reference to "songs" - instead define it as a ForeignKey,
|
||||||
songs = models.ManyToManyField(Song)
|
#and do lookups via song_set
|
||||||
|
|
||||||
#Backup settings
|
#Backup settings
|
||||||
backup_location = models.CharField(max_length = 255, default = "/dev/null")
|
backup_location = models.CharField(max_length = 255, default = "/dev/null")
|
||||||
@ -53,7 +51,7 @@ class Archive (models.Model):
|
|||||||
|
|
||||||
#It's hackish, but far fewer transactions to delete everything first, and add it all back.
|
#It's hackish, but far fewer transactions to delete everything first, and add it all back.
|
||||||
#If we get interrupted, just re-run it.
|
#If we get interrupted, just re-run it.
|
||||||
self.songs.all().delete()
|
song_set.all().delete()
|
||||||
|
|
||||||
#Add new songs
|
#Add new songs
|
||||||
for dirname, dirnames, filenames in os.walk(self.root_folder):
|
for dirname, dirnames, filenames in os.walk(self.root_folder):
|
||||||
@ -63,16 +61,16 @@ class Archive (models.Model):
|
|||||||
full_url = os.path.abspath(rel_url)
|
full_url = os.path.abspath(rel_url)
|
||||||
new_song = Song(url = full_url)
|
new_song = Song(url = full_url)
|
||||||
new_song.save()
|
new_song.save()
|
||||||
self.songs.add(new_song)
|
song_set.add(new_song)
|
||||||
|
|
||||||
def _update_song_metadata(self, use_echonest = False, progress_callback = lambda x, y: None):
|
def _update_song_metadata(self, use_echonest = False, progress_callback = lambda x, y: None):
|
||||||
"""Scan every song in this archive (database only) and make sure all songs are correct
|
"""Scan every song in this archive (database only) and make sure all songs are correct
|
||||||
The progress_callback function is called with the current song being operated on first, and the total songs second."""
|
The progress_callback function is called with the current song being operated on first, and the total songs second."""
|
||||||
#This method operates only on the songs that are in the database - if you need to make
|
#This method operates only on the songs that are in the database - if you need to make
|
||||||
#sure that new songs are added, use the _scan_filesystem() method in addition
|
#sure that new songs are added, use the _scan_filesystem() method in addition
|
||||||
total_songs = self.songs.count()
|
total_songs = song_set.count()
|
||||||
|
|
||||||
for index, song in enumerate(self.songs.all()):
|
for index, song in enumerate(song_set.all()):
|
||||||
song.populate_metadata(use_echonest = use_echonest)
|
song.populate_metadata(use_echonest = use_echonest)
|
||||||
song.save()
|
song.save()
|
||||||
progress_callback(index + 1, total_songs)
|
progress_callback(index + 1, total_songs)
|
||||||
@ -133,9 +131,9 @@ class Archive (models.Model):
|
|||||||
"""
|
"""
|
||||||
import os, shutil, errno
|
import os, shutil, errno
|
||||||
|
|
||||||
total_songs = self.songs.count()
|
total_songs = song_set.count()
|
||||||
|
|
||||||
for index, song in enumerate(self.songs.all()):
|
for index, song in enumerate(song_set.all()):
|
||||||
_current_filename = os.path.basename(song.url)
|
_current_filename = os.path.basename(song.url)
|
||||||
_current_filename_no_extension = os.path.splitext(_current_filename)[0]
|
_current_filename_no_extension = os.path.splitext(_current_filename)[0]
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from Melodia import melodia_settings
|
from Melodia import melodia_settings
|
||||||
|
|
||||||
|
from archive import Archive
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import os.path
|
||||||
"""
|
"""
|
||||||
The Song model
|
The Song model
|
||||||
Each instance of a Song represents a single music file.
|
Each instance of a Song represents a single music file.
|
||||||
@ -63,6 +66,9 @@ class Song (models.Model):
|
|||||||
skip_count = models.IntegerField(default = _default_int)
|
skip_count = models.IntegerField(default = _default_int)
|
||||||
rating = models.IntegerField(default = _default_int, choices = _default_rating_choices)
|
rating = models.IntegerField(default = _default_int, choices = _default_rating_choices)
|
||||||
|
|
||||||
|
#Link back to the archive this comes from
|
||||||
|
parent_archive = models.ForeignKey(Archive)
|
||||||
|
|
||||||
#Set a static reference to the rating options
|
#Set a static reference to the rating options
|
||||||
RATING_DEFAULT = _default_rating
|
RATING_DEFAULT = _default_rating
|
||||||
RATING_BAD = _default_rating_bad
|
RATING_BAD = _default_rating_bad
|
||||||
@ -71,6 +77,10 @@ class Song (models.Model):
|
|||||||
RATING_GOOD = _default_rating_good
|
RATING_GOOD = _default_rating_good
|
||||||
RATING_EXCELLENT = _default_rating_excellent
|
RATING_EXCELLENT = _default_rating_excellent
|
||||||
|
|
||||||
|
def _get_full_url(self):
|
||||||
|
"Combine this song's URL with the URL of its parent"
|
||||||
|
return os.path.join(parent_archive.root_folder, self.url)
|
||||||
|
|
||||||
def _file_not_changed(self):
|
def _file_not_changed(self):
|
||||||
"Make sure the hash for this file is valid - return True if it has not changed."
|
"Make sure the hash for this file is valid - return True if it has not changed."
|
||||||
#Overload the hash function with whatever Melodia as a whole is using
|
#Overload the hash function with whatever Melodia as a whole is using
|
||||||
@ -79,7 +89,7 @@ class Song (models.Model):
|
|||||||
#Check if there's a hash entry - if there is, the song may not have changed,
|
#Check if there's a hash entry - if there is, the song may not have changed,
|
||||||
#and we can go ahead and return
|
#and we can go ahead and return
|
||||||
if self.file_hash != None:
|
if self.file_hash != None:
|
||||||
song_file = open(self.url, 'rb')
|
song_file = open(self._get_full_url, 'rb')
|
||||||
current_file_hash = hash(song_file.read())
|
current_file_hash = hash(song_file.read())
|
||||||
|
|
||||||
if current_file_hash == self.file_hash:
|
if current_file_hash == self.file_hash:
|
||||||
@ -94,10 +104,10 @@ class Song (models.Model):
|
|||||||
#Overload the hash function with whatever Melodia as a whole is using
|
#Overload the hash function with whatever Melodia as a whole is using
|
||||||
from Melodia.melodia_settings import HASH_FUNCTION as hash
|
from Melodia.melodia_settings import HASH_FUNCTION as hash
|
||||||
|
|
||||||
file_handle = open(self.url, 'rb')
|
file_handle = open(self._get_full_url, 'rb')
|
||||||
|
|
||||||
self.file_hash = hash(file_handle.read())
|
self.file_hash = hash(file_handle.read())
|
||||||
self.file_size = os.stat(self.url).st_size
|
self.file_size = os.stat(self._get_full_url).st_size
|
||||||
|
|
||||||
def _grab_metadata_echonest(self):
|
def _grab_metadata_echonest(self):
|
||||||
"Populate this song's metadata using EchoNest"
|
"Populate this song's metadata using EchoNest"
|
||||||
@ -110,8 +120,8 @@ class Song (models.Model):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
#Use mutagen to scan local metadata - don't update anything else (i.e. play_count)
|
#Use mutagen to scan local metadata - don't update anything else (i.e. play_count)
|
||||||
track = mutagen.File(self.url)
|
track = mutagen.File(self._get_full_url)
|
||||||
track_easy = mutagen.File(self.url, easy=True)
|
track_easy = mutagen.File(self._get_full_url, easy=True)
|
||||||
|
|
||||||
self.title = track_easy['title'][0] or _default_string
|
self.title = track_easy['title'][0] or _default_string
|
||||||
self.artist = track_easy['artist'][0] or _default_string
|
self.artist = track_easy['artist'][0] or _default_string
|
||||||
|
Loading…
Reference in New Issue
Block a user