From 17960be548d25e8c97cc0ffec78abe6717d2d223 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Tue, 12 Feb 2013 15:02:08 -0500 Subject: [PATCH] Restructure relationship b/w Songs and Archives Songs now have a ForeignKey to Archive - one song can not be part of many Archives. --- archiver/archive.py | 18 ++++++++---------- archiver/song.py | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/archiver/archive.py b/archiver/archive.py index 1eececd..f473de6 100644 --- a/archiver/archive.py +++ b/archiver/archive.py @@ -1,7 +1,5 @@ from django.db import models -from song import Song - """ This is the archive model for the archiving backend of Melodia. 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 root_folder = models.CharField(max_length = 255) - #And a reference to the songs in this archive - songs = models.ManyToManyField(Song) + #We've removed the reference to "songs" - instead define it as a ForeignKey, + #and do lookups via song_set #Backup settings 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. #If we get interrupted, just re-run it. - self.songs.all().delete() + song_set.all().delete() #Add new songs 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) new_song = Song(url = full_url) 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): """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.""" #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 - 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.save() progress_callback(index + 1, total_songs) @@ -133,9 +131,9 @@ class Archive (models.Model): """ 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_no_extension = os.path.splitext(_current_filename)[0] diff --git a/archiver/song.py b/archiver/song.py index d433869..97ba257 100644 --- a/archiver/song.py +++ b/archiver/song.py @@ -1,7 +1,10 @@ from django.db import models from Melodia import melodia_settings +from archive import Archive + import datetime +import os.path """ The Song model 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) 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 RATING_DEFAULT = _default_rating RATING_BAD = _default_rating_bad @@ -71,6 +77,10 @@ class Song (models.Model): RATING_GOOD = _default_rating_good 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): "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 @@ -79,7 +89,7 @@ class Song (models.Model): #Check if there's a hash entry - if there is, the song may not have changed, #and we can go ahead and return 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()) 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 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_size = os.stat(self.url).st_size + self.file_size = os.stat(self._get_full_url).st_size def _grab_metadata_echonest(self): "Populate this song's metadata using EchoNest" @@ -110,8 +120,8 @@ class Song (models.Model): try: #Use mutagen to scan local metadata - don't update anything else (i.e. play_count) - track = mutagen.File(self.url) - track_easy = mutagen.File(self.url, easy=True) + track = mutagen.File(self._get_full_url) + track_easy = mutagen.File(self._get_full_url, easy=True) self.title = track_easy['title'][0] or _default_string self.artist = track_easy['artist'][0] or _default_string