diff --git a/cocoa/base/ui/main_menu.py b/cocoa/base/ui/main_menu.py index 8696f501..3f9e8255 100644 --- a/cocoa/base/ui/main_menu.py +++ b/cocoa/base/ui/main_menu.py @@ -32,8 +32,6 @@ fileMenu.addItem("Export Results to XHTML", Action(owner.model, 'exportToXHTML') fileMenu.addItem("Export Results to CSV", Action(owner.model, 'exportToCSV')) if edition == 'pe': fileMenu.addItem("Clear Picture Cache", Action(owner, 'clearPictureCache'), 'cmd+shift+p') -elif edition == 'me': - fileMenu.addItem("Remove Dead Tracks in iTunes", Action(owner, 'removeDeadTracks')) editMenu.addItem("Mark All", Action(None, 'markAll'), 'cmd+a') editMenu.addItem("Mark None", Action(None, 'markNone'), 'cmd+shift+a') diff --git a/cocoa/inter/app_me.py b/cocoa/inter/app_me.py index 75c2196d..70e20b3f 100644 --- a/cocoa/inter/app_me.py +++ b/cocoa/inter/app_me.py @@ -1,261 +1,21 @@ -# Created By: Virgil Dupras -# Created On: 2006/11/16 -# Copyright 2015 Hardcoded Software (http://www.hardcoded.net) +# Copyright 2016 Hardcoded Software (http://www.hardcoded.net) # # This software is licensed under the "GPLv3" License as described in the "LICENSE" file, # which should be included with this package. The terms are also available at # http://www.gnu.org/licenses/gpl-3.0.html -import logging -import plistlib -import time -import os.path as op -from appscript import app, its, k, CommandError, ApplicationNotFoundError -from . import tunes - -from cocoa import as_fetch, proxy from hscommon.trans import trget -from hscommon.path import Path -from hscommon.util import remove_invalid_xml -from core import directories -from core.app import JobType, JOBID2TITLE from core.scanner import ScanType -from core_me.app import DupeGuru as DupeGuruBase -from core_me import fs +from core_me.app import DupeGuru as DupeGuruME from .app import PyDupeGuruBase tr = trget('ui') -JobType.RemoveDeadTracks = 'jobRemoveDeadTracks' -JobType.ScanDeadTracks = 'jobScanDeadTracks' - -JOBID2TITLE.update({ - JobType.RemoveDeadTracks: tr("Removing dead tracks from your iTunes Library"), - JobType.ScanDeadTracks: tr("Scanning the iTunes Library"), -}) - -ITUNES = 'iTunes' -ITUNES_PATH = Path('iTunes Library') - -def get_itunes_library(a): - try: - [source] = [s for s in a.sources(timeout=0) if s.kind(timeout=0) == k.library] - [library] = source.library_playlists(timeout=0) - return library - except ValueError: - logging.warning('Some unexpected iTunes configuration encountered') - return None - -class ITunesSong(fs.MusicFile): - def __init__(self, song_data): - path = Path(proxy.url2path_(song_data['Location'])) - fs.MusicFile.__init__(self, path) - self.id = song_data['Track ID'] - - def remove_from_library(self): - try: - a = app(ITUNES, terms=tunes) - library = get_itunes_library(a) - if library is None: - return - [song] = library.file_tracks[its.database_ID == self.id]() - a.delete(song, timeout=0) - except ValueError: - msg = "Could not find song '{}' (trackid: {}) in iTunes Library".format(str(self.path), self.id) - raise EnvironmentError(msg) - except (CommandError, RuntimeError) as e: - raise EnvironmentError(str(e)) - - display_folder_path = ITUNES_PATH - -def get_itunes_database_path(): - plisturls = proxy.prefValue_inDomain_('iTunesRecentDatabases', 'com.apple.iApps') - if not plisturls: - raise directories.InvalidPathError() - plistpath = proxy.url2path_(plisturls[0]) - return Path(plistpath) - -def get_itunes_songs(plistpath): - if not plistpath.exists(): - return [] - s = plistpath.open('rt', encoding='utf-8').read() - # iTunes sometimes produces XML files with invalid characters in it. - s = remove_invalid_xml(s, replace_with='') - plist = plistlib.readPlistFromBytes(s.encode('utf-8')) - result = [] - for song_data in plist['Tracks'].values(): - try: - if song_data['Track Type'] != 'File': - continue - song = ITunesSong(song_data) - except KeyError: # No "Track Type", "Location" or "Track ID" key in track - continue - if song.path.exists(): - result.append(song) - return result - -class Directories(directories.Directories): - def __init__(self): - directories.Directories.__init__(self) - try: - self.itunes_libpath = get_itunes_database_path() - except directories.InvalidPathError: - self.itunes_libpath = None - - def _get_files(self, from_path, fileclasses, j): - if from_path == ITUNES_PATH: - if self.itunes_libpath is None: - return [] - is_ref = self.get_state(from_path) == directories.DirectoryState.Reference - songs = get_itunes_songs(self.itunes_libpath) - for song in songs: - song.is_ref = is_ref - return songs - else: - return directories.Directories._get_files(self, from_path, fileclasses, j) - - @staticmethod - def get_subfolders(path): - if path == ITUNES_PATH: - return [] - else: - return directories.Directories.get_subfolders(path) - - def add_path(self, path): - if path == ITUNES_PATH: - if path not in self: - self._dirs.append(path) - else: - directories.Directories.add_path(self, path) - - def has_itunes_path(self): - return any(path == ITUNES_PATH for path in self._dirs) - - def has_any_file(self): - # If we don't do that, it causes a hangup in the GUI when we click Start Scanning because - # checking if there's any file to scan involves reading the whole library. If we have the - # iTunes library, we assume we have at least one file. - if self.has_itunes_path(): - return True - else: - return directories.Directories.has_any_file(self) - - -class DupeGuruME(DupeGuruBase): - def __init__(self, view): - DupeGuruBase.__init__(self, view) - self.directories = Directories() - self.dead_tracks = [] - - def _do_delete(self, j, *args): - def op(dupe): - j.add_progress() - return self._do_delete_dupe(dupe, *args) - - marked = [dupe for dupe in self.results.dupes if self.results.is_marked(dupe)] - j.start_job(self.results.mark_count, tr("Sending dupes to the Trash")) - if any(isinstance(dupe, ITunesSong) for dupe in marked): - j.add_progress(0, desc=tr("Talking to iTunes. Don't touch it!")) - try: - a = app(ITUNES, terms=tunes) - a.activate(timeout=0) - except (CommandError, RuntimeError, ApplicationNotFoundError): - pass - self.results.perform_on_marked(op, True) - - def _do_delete_dupe(self, dupe, *args): - if isinstance(dupe, ITunesSong): - dupe.remove_from_library() - DupeGuruBase._do_delete_dupe(self, dupe, *args) - - def _create_file(self, path): - if (self.directories.itunes_libpath is not None) and (path in self.directories.itunes_libpath.parent()): - if not hasattr(self, 'itunes_songs'): - songs = get_itunes_songs(self.directories.itunes_libpath) - self.itunes_songs = {song.path: song for song in songs} - if path in self.itunes_songs: - return self.itunes_songs[path] - else: - pass # We'll return the default file type, as per the last line of this method - return DupeGuruBase._create_file(self, path) - - def _job_completed(self, jobid): - # XXX Just before release, I'm realizing that this piece of code below is why I was passing - # job exception as an argument to _job_completed(). I have to comment it for now. It's not - # the end of the world, but I should find an elegant solution to this at some point. - # if (jobid in {JobType.RemoveDeadTracks, JobType.ScanDeadTracks}) and (exc is not None): - # msg = tr("There were communication problems with iTunes. The operation couldn't be completed.") - # self.view.show_message(msg) - # return True - if jobid == JobType.ScanDeadTracks: - dead_tracks_count = len(self.dead_tracks) - if dead_tracks_count > 0: - msg = tr("Your iTunes Library contains %d dead tracks ready to be removed. Continue?") - if self.view.ask_yes_no(msg % dead_tracks_count): - self.remove_dead_tracks() - else: - msg = tr("You have no dead tracks in your iTunes Library") - self.view.show_message(msg) - if jobid == JobType.Load: - if hasattr(self, 'itunes_songs'): - # If we load another file, we want a refresh song list - del self.itunes_songs - DupeGuruBase._job_completed(self, jobid) - - def copy_or_move(self, dupe, copy, destination, dest_type): - if isinstance(dupe, ITunesSong): - copy = True - return DupeGuruBase.copy_or_move(self, dupe, copy, destination, dest_type) - - def start_scanning(self): - if self.directories.has_itunes_path(): - try: - app(ITUNES, terms=tunes) - except ApplicationNotFoundError: - self.view.show_message(tr("The iTunes application couldn't be found.")) - return - DupeGuruBase.start_scanning(self) - - def remove_dead_tracks(self): - def do(j): - a = app(ITUNES, terms=tunes) - a.activate(timeout=0) - for index, track in enumerate(j.iter_with_progress(self.dead_tracks)): - if index % 100 == 0: - time.sleep(.1) - try: - track.delete(timeout=0) - except CommandError as e: - logging.warning('Error while trying to remove a track from iTunes: %s' % str(e)) - - self._start_job(JobType.RemoveDeadTracks, do) - - def scan_dead_tracks(self): - def do(j): - a = app(ITUNES, terms=tunes) - a.activate(timeout=0) - library = get_itunes_library(a) - if library is None: - return - self.dead_tracks = [] - tracks = as_fetch(library.file_tracks, k.file_track) - for index, track in enumerate(j.iter_with_progress(tracks)): - if index % 100 == 0: - time.sleep(.1) - if track.location(timeout=0) == k.missing_value: - self.dead_tracks.append(track) - logging.info('Found %d dead tracks' % len(self.dead_tracks)) - - self._start_job(JobType.ScanDeadTracks, do) - class PyDupeGuru(PyDupeGuruBase): def __init__(self): self._init(DupeGuruME) - def scanDeadTracks(self): - self.model.scan_dead_tracks() - #---Properties def setMinMatchPercentage_(self, percentage: int): self.model.options['min_match_percentage'] = percentage diff --git a/cocoa/inter/tunes.py b/cocoa/inter/tunes.py deleted file mode 100644 index d1f41c06..00000000 --- a/cocoa/inter/tunes.py +++ /dev/null @@ -1,282 +0,0 @@ -# Taken from https://github.com/abarnert/itunesterms - -version = 1.1 -path = '/Applications/iTunes.app' - -classes = \ -[('print_settings', b'pset'), - ('application', b'capp'), - ('artwork', b'cArt'), - ('audio_CD_playlist', b'cCDP'), - ('audio_CD_track', b'cCDT'), - ('browser_window', b'cBrW'), - ('device_playlist', b'cDvP'), - ('device_track', b'cDvT'), - ('encoder', b'cEnc'), - ('EQ_preset', b'cEQP'), - ('EQ_window', b'cEQW'), - ('file_track', b'cFlT'), - ('folder_playlist', b'cFoP'), - ('item', b'cobj'), - ('library_playlist', b'cLiP'), - ('playlist', b'cPly'), - ('playlist_window', b'cPlW'), - ('radio_tuner_playlist', b'cRTP'), - ('shared_track', b'cShT'), - ('source', b'cSrc'), - ('track', b'cTrk'), - ('URL_track', b'cURT'), - ('user_playlist', b'cUsP'), - ('visual', b'cVis'), - ('window', b'cwin')] - -enums = \ -[('track_listing', b'kTrk'), - ('album_listing', b'kAlb'), - ('cd_insert', b'kCDi'), - ('standard', b'lwst'), - ('detailed', b'lwdt'), - ('stopped', b'kPSS'), - ('playing', b'kPSP'), - ('paused', b'kPSp'), - ('fast_forwarding', b'kPSF'), - ('rewinding', b'kPSR'), - ('off', b'kRpO'), - ('one', b'kRp1'), - ('all', b'kAll'), - ('small', b'kVSS'), - ('medium', b'kVSM'), - ('large', b'kVSL'), - ('library', b'kLib'), - ('iPod', b'kPod'), - ('audio_CD', b'kACD'), - ('MP3_CD', b'kMCD'), - ('device', b'kDev'), - ('radio_tuner', b'kTun'), - ('shared_library', b'kShd'), - ('unknown', b'kUnk'), - ('albums', b'kSrL'), - ('artists', b'kSrR'), - ('composers', b'kSrC'), - ('displayed', b'kSrV'), - ('songs', b'kSrS'), - ('none', b'kNon'), - ('Books', b'kSpA'), - ('folder', b'kSpF'), - ('Genius', b'kSpG'), - ('iTunes_U', b'kSpU'), - ('Library', b'kSpL'), - ('Movies', b'kSpI'), - ('Music', b'kSpZ'), - ('Party_Shuffle', b'kSpS'), - ('Podcasts', b'kSpP'), - ('Purchased_Music', b'kSpM'), - ('TV_Shows', b'kSpT'), - ('movie', b'kVdM'), - ('music_video', b'kVdV'), - ('TV_show', b'kVdT'), - ('user', b'kRtU'), - ('computed', b'kRtC')] - -properties = \ -[('copies', b'lwcp'), - ('collating', b'lwcl'), - ('starting_page', b'lwfp'), - ('ending_page', b'lwlp'), - ('pages_across', b'lwla'), - ('pages_down', b'lwld'), - ('error_handling', b'lweh'), - ('requested_print_time', b'lwqt'), - ('printer_features', b'lwpf'), - ('fax_number', b'faxn'), - ('target_printer', b'trpr'), - ('current_encoder', b'pEnc'), - ('current_EQ_preset', b'pEQP'), - ('current_playlist', b'pPla'), - ('current_stream_title', b'pStT'), - ('current_stream_URL', b'pStU'), - ('current_track', b'pTrk'), - ('current_visual', b'pVis'), - ('EQ_enabled', b'pEQ '), - ('fixed_indexing', b'pFix'), - ('frontmost', b'pisf'), - ('full_screen', b'pFSc'), - ('name', b'pnam'), - ('mute', b'pMut'), - ('player_position', b'pPos'), - ('player_state', b'pPlS'), - ('selection', b'sele'), - ('sound_volume', b'pVol'), - ('version', b'vers'), - ('visuals_enabled', b'pVsE'), - ('visual_size', b'pVSz'), - ('data', b'pPCT'), - ('description', b'pDes'), - ('downloaded', b'pDlA'), - ('format', b'pFmt'), - ('kind', b'pKnd'), - ('raw_data', b'pRaw'), - ('artist', b'pArt'), - ('compilation', b'pAnt'), - ('composer', b'pCmp'), - ('disc_count', b'pDsC'), - ('disc_number', b'pDsN'), - ('genre', b'pGen'), - ('year', b'pYr '), - ('location', b'pLoc'), - ('minimized', b'pMin'), - ('view', b'pPly'), - ('band_1', b'pEQ1'), - ('band_2', b'pEQ2'), - ('band_3', b'pEQ3'), - ('band_4', b'pEQ4'), - ('band_5', b'pEQ5'), - ('band_6', b'pEQ6'), - ('band_7', b'pEQ7'), - ('band_8', b'pEQ8'), - ('band_9', b'pEQ9'), - ('band_10', b'pEQ0'), - ('modifiable', b'pMod'), - ('preamp', b'pEQA'), - ('update_tracks', b'pUTC'), - ('container', b'ctnr'), - ('id', b'ID '), - ('index', b'pidx'), - ('persistent_ID', b'pPIS'), - ('duration', b'pDur'), - ('parent', b'pPlP'), - ('shuffle', b'pShf'), - ('size', b'pSiz'), - ('song_repeat', b'pRpt'), - ('special_kind', b'pSpK'), - ('time', b'pTim'), - ('visible', b'pvis'), - ('capacity', b'capa'), - ('free_space', b'frsp'), - ('album', b'pAlb'), - ('album_artist', b'pAlA'), - ('album_rating', b'pAlR'), - ('album_rating_kind', b'pARk'), - ('bit_rate', b'pBRt'), - ('bookmark', b'pBkt'), - ('bookmarkable', b'pBkm'), - ('bpm', b'pBPM'), - ('category', b'pCat'), - ('comment', b'pCmt'), - ('database_ID', b'pDID'), - ('date_added', b'pAdd'), - ('enabled', b'enbl'), - ('episode_ID', b'pEpD'), - ('episode_number', b'pEpN'), - ('EQ', b'pEQp'), - ('finish', b'pStp'), - ('gapless', b'pGpl'), - ('grouping', b'pGrp'), - ('long_description', b'pLds'), - ('lyrics', b'pLyr'), - ('modification_date', b'asmo'), - ('played_count', b'pPlC'), - ('played_date', b'pPlD'), - ('podcast', b'pTPc'), - ('rating', b'pRte'), - ('rating_kind', b'pRtk'), - ('release_date', b'pRlD'), - ('sample_rate', b'pSRt'), - ('season_number', b'pSeN'), - ('shufflable', b'pSfa'), - ('skipped_count', b'pSkC'), - ('skipped_date', b'pSkD'), - ('show', b'pShw'), - ('sort_album', b'pSAl'), - ('sort_artist', b'pSAr'), - ('sort_album_artist', b'pSAA'), - ('sort_name', b'pSNm'), - ('sort_composer', b'pSCm'), - ('sort_show', b'pSSN'), - ('start', b'pStr'), - ('track_count', b'pTrC'), - ('track_number', b'pTrN'), - ('unplayed', b'pUnp'), - ('video_kind', b'pVdK'), - ('volume_adjustment', b'pAdj'), - ('address', b'pURL'), - ('shared', b'pShr'), - ('smart', b'pSmt'), - ('bounds', b'pbnd'), - ('closeable', b'hclb'), - ('collapseable', b'pWSh'), - ('collapsed', b'wshd'), - ('position', b'ppos'), - ('resizable', b'prsz'), - ('zoomable', b'iszm'), - ('zoomed', b'pzum')] - -elements = \ -[('artworks', b'cArt'), - ('audio_CD_playlists', b'cCDP'), - ('audio_CD_tracks', b'cCDT'), - ('browser_windows', b'cBrW'), - ('device_playlists', b'cDvP'), - ('device_tracks', b'cDvT'), - ('encoders', b'cEnc'), - ('EQ_presets', b'cEQP'), - ('EQ_windows', b'cEQW'), - ('file_tracks', b'cFlT'), - ('folder_playlists', b'cFoP'), - ('items', b'cobj'), - ('library_playlists', b'cLiP'), - ('playlists', b'cPly'), - ('playlist_windows', b'cPlW'), - ('radio_tuner_playlists', b'cRTP'), - ('shared_tracks', b'cShT'), - ('sources', b'cSrc'), - ('tracks', b'cTrk'), - ('URL_tracks', b'cURT'), - ('user_playlists', b'cUsP'), - ('visuals', b'cVis'), - ('windows', b'cwin'), - ('application', b'capp'), - ('print_settings', b'pset')] - -commands = \ -[('set', b'coresetd', [('to', b'data')]), - ('exists', b'coredoex', []), - ('move', b'coremove', [('to', b'insh')]), - ('subscribe', b'hookpSub', []), - ('playpause', b'hookPlPs', []), - ('download', b'hookDwnl', []), - ('close', b'coreclos', []), - ('open', b'aevtodoc', []), - ('open_location', b'GURLGURL', []), - ('quit', b'aevtquit', []), - ('pause', b'hookPaus', []), - ('make', - 'corecrel', - [('new', b'kocl'), ('at', b'insh'), ('with_properties', b'prdt')]), - ('duplicate', b'coreclon', [('to', b'insh')]), - ('print_', - 'aevtpdoc', - [('print_dialog', b'pdlg'), - ('with_properties', b'prdt'), - ('kind', b'pKnd'), - ('theme', b'pThm')]), - ('add', b'hookAdd ', [('to', b'insh')]), - ('rewind', b'hookRwnd', []), - ('play', b'hookPlay', [('once', b'POne')]), - ('run', b'aevtoapp', []), - ('resume', b'hookResu', []), - ('updatePodcast', b'hookUpd1', []), - ('next_track', b'hookNext', []), - ('stop', b'hookStop', []), - ('search', b'hookSrch', [('for_', b'pTrm'), ('only', b'pAre')]), - ('updateAllPodcasts', b'hookUpdp', []), - ('update', b'hookUpdt', []), - ('previous_track', b'hookPrev', []), - ('fast_forward', b'hookFast', []), - ('count', b'corecnte', [('each', b'kocl')]), - ('reveal', b'hookRevl', []), - ('convert', b'hookConv', []), - ('eject', b'hookEjct', []), - ('back_track', b'hookBack', []), - ('refresh', b'hookRfrs', []), - ('delete', b'coredelo', [])] diff --git a/cocoa/me/AppDelegate.h b/cocoa/me/AppDelegate.h index f525b0e9..79cf3e41 100644 --- a/cocoa/me/AppDelegate.h +++ b/cocoa/me/AppDelegate.h @@ -12,5 +12,4 @@ http://www.gnu.org/licenses/gpl-3.0.html #import "PyDupeGuru.h" @interface AppDelegate : AppDelegateBase {} -- (void)removeDeadTracks; @end diff --git a/cocoa/me/AppDelegate.m b/cocoa/me/AppDelegate.m index c7a3fa5d..a9cf2482 100644 --- a/cocoa/me/AppDelegate.m +++ b/cocoa/me/AppDelegate.m @@ -1,5 +1,5 @@ /* -Copyright 2015 Hardcoded Software (http://www.hardcoded.net) +Copyright 2016 Hardcoded Software (http://www.hardcoded.net) This software is licensed under the "GPLv3" License as described in the "LICENSE" file, which should be included with this package. The terms are also available at @@ -12,7 +12,6 @@ http://www.gnu.org/licenses/gpl-3.0.html #import "ValueTransformers.h" #import "Dialogs.h" #import "DetailsPanel.h" -#import "DirectoryPanel.h" #import "ResultWindow.h" #import "Consts.h" @@ -48,21 +47,11 @@ http://www.gnu.org/licenses/gpl-3.0.html - (NSString *)homepageURL { - return @"http://www.hardcoded.net/dupeguru_me/"; + return @"https://www.hardcoded.net/dupeguru_me/"; } - (ResultWindowBase *)createResultWindow { return [[ResultWindow alloc] initWithParentApp:self]; } - -- (DirectoryPanel *)createDirectoryPanel -{ - return [[DirectoryPanelME alloc] initWithParentApp:self]; -} - -- (void)removeDeadTracks -{ - [(ResultWindow *)[self resultWindow] removeDeadTracks]; -} @end diff --git a/cocoa/me/Consts.h b/cocoa/me/Consts.h deleted file mode 100644 index ba26a877..00000000 --- a/cocoa/me/Consts.h +++ /dev/null @@ -1,11 +0,0 @@ -/* -Copyright 2015 Hardcoded Software (http://www.hardcoded.net) - -This software is licensed under the "GPLv3" License as described in the "LICENSE" file, -which should be included with this package. The terms are also available at -http://www.gnu.org/licenses/gpl-3.0.html -*/ - -#import "../base/Consts.h" - -#define jobScanDeadTracks @"jobScanDeadTracks" \ No newline at end of file diff --git a/cocoa/me/DirectoryPanel.h b/cocoa/me/DirectoryPanel.h deleted file mode 100644 index 5ebd08d2..00000000 --- a/cocoa/me/DirectoryPanel.h +++ /dev/null @@ -1,16 +0,0 @@ -/* -Copyright 2015 Hardcoded Software (http://www.hardcoded.net) - -This software is licensed under the "GPLv3" License as described in the "LICENSE" file, -which should be included with this package. The terms are also available at -http://www.gnu.org/licenses/gpl-3.0.html -*/ - -#import -#import "../base/DirectoryPanel.h" - -@interface DirectoryPanelME : DirectoryPanel -{ -} -- (IBAction)addiTunes:(id)sender; -@end diff --git a/cocoa/me/DirectoryPanel.m b/cocoa/me/DirectoryPanel.m deleted file mode 100644 index 398ec64e..00000000 --- a/cocoa/me/DirectoryPanel.m +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2015 Hardcoded Software (http://www.hardcoded.net) - -This software is licensed under the "GPLv3" License as described in the "LICENSE" file, -which should be included with this package. The terms are also available at -http://www.gnu.org/licenses/gpl-3.0.html -*/ - -#import "DirectoryPanel.h" - -@implementation DirectoryPanelME -- (id)initWithParentApp:(id)aParentApp -{ - self = [super initWithParentApp:aParentApp]; - _alwaysShowPopUp = YES; - return self; -} - -- (void)fillPopUpMenu -{ - [super fillPopUpMenu]; - NSMenu *m = [addButtonPopUp menu]; - NSMenuItem *mi = [m insertItemWithTitle:NSLocalizedString(@"Add iTunes Library", @"") action:@selector(addiTunes:) - keyEquivalent:@"" atIndex:1]; - [mi setTarget:self]; -} - -- (IBAction)addiTunes:(id)sender -{ - [self addDirectory:@"iTunes Library"]; -} -@end diff --git a/cocoa/me/ResultWindow.h b/cocoa/me/ResultWindow.h index f64dd1d3..707edb5b 100644 --- a/cocoa/me/ResultWindow.h +++ b/cocoa/me/ResultWindow.h @@ -10,5 +10,4 @@ http://www.gnu.org/licenses/gpl-3.0.html #import "ResultWindowBase.h" @interface ResultWindow : ResultWindowBase {} -- (void)removeDeadTracks; @end diff --git a/cocoa/me/ResultWindow.m b/cocoa/me/ResultWindow.m index a1e68568..27a0f449 100644 --- a/cocoa/me/ResultWindow.m +++ b/cocoa/me/ResultWindow.m @@ -68,10 +68,4 @@ http://www.gnu.org/licenses/gpl-3.0.html [[c dataCell] setAlignment:NSRightTextAlignment]; [[table columns] restoreColumns]; } - -/* Actions */ -- (void)removeDeadTracks -{ - [model scanDeadTracks]; -} @end