2009-08-05 08:59:46 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2006/11/16
|
2011-04-12 08:04:01 +00:00
|
|
|
# Copyright 2011 Hardcoded Software (http://www.hardcoded.net)
|
2009-08-05 08:59:46 +00:00
|
|
|
#
|
2010-09-30 10:17:41 +00:00
|
|
|
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
2009-08-05 08:59:46 +00:00
|
|
|
# which should be included with this package. The terms are also available at
|
2010-09-30 10:17:41 +00:00
|
|
|
# http://www.hardcoded.net/licenses/bsd_license
|
2009-08-05 08:59:46 +00:00
|
|
|
|
2009-06-01 09:55:11 +00:00
|
|
|
import logging
|
|
|
|
from appscript import app, k, CommandError
|
|
|
|
import time
|
2011-09-20 22:40:27 +00:00
|
|
|
import os.path as op
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2012-01-05 21:57:31 +00:00
|
|
|
from cocoa import as_fetch
|
2011-01-18 16:33:33 +00:00
|
|
|
from hscommon.trans import tr
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2011-09-21 17:55:26 +00:00
|
|
|
from core.app import JobType
|
2012-01-16 15:30:45 +00:00
|
|
|
from core.scanner import ScanType
|
2011-09-21 20:02:13 +00:00
|
|
|
from core_me.app import DupeGuru as DupeGuruBase
|
2012-01-16 15:30:45 +00:00
|
|
|
from .app import JOBID2TITLE, PyDupeGuruBase
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2011-09-21 17:55:26 +00:00
|
|
|
JobType.RemoveDeadTracks = 'jobRemoveDeadTracks'
|
|
|
|
JobType.ScanDeadTracks = 'jobScanDeadTracks'
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2009-10-23 14:35:51 +00:00
|
|
|
JOBID2TITLE.update({
|
2011-09-21 17:55:26 +00:00
|
|
|
JobType.RemoveDeadTracks: tr("Removing dead tracks from your iTunes Library"),
|
|
|
|
JobType.ScanDeadTracks: tr("Scanning the iTunes Library"),
|
2009-06-01 09:55:11 +00:00
|
|
|
})
|
|
|
|
|
2009-10-23 14:35:51 +00:00
|
|
|
class DupeGuruME(DupeGuruBase):
|
2011-09-20 22:40:27 +00:00
|
|
|
def __init__(self, view, appdata):
|
|
|
|
appdata = op.join(appdata, 'dupeGuru Music Edition')
|
|
|
|
DupeGuruBase.__init__(self, view, appdata)
|
2009-06-01 09:55:11 +00:00
|
|
|
self.dead_tracks = []
|
|
|
|
|
|
|
|
def remove_dead_tracks(self):
|
|
|
|
def do(j):
|
|
|
|
a = app('iTunes')
|
2009-06-10 13:54:24 +00:00
|
|
|
a.activate(timeout=0)
|
2009-06-01 09:55:11 +00:00
|
|
|
for index, track in enumerate(j.iter_with_progress(self.dead_tracks)):
|
|
|
|
if index % 100 == 0:
|
|
|
|
time.sleep(.1)
|
|
|
|
try:
|
2009-06-10 13:54:24 +00:00
|
|
|
track.delete(timeout=0)
|
2009-06-01 09:55:11 +00:00
|
|
|
except CommandError as e:
|
2010-08-11 14:39:06 +00:00
|
|
|
logging.warning('Error while trying to remove a track from iTunes: %s' % str(e))
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2011-09-21 17:55:26 +00:00
|
|
|
self.view.start_job(JobType.RemoveDeadTracks, do)
|
2009-06-01 09:55:11 +00:00
|
|
|
|
|
|
|
def scan_dead_tracks(self):
|
|
|
|
def do(j):
|
|
|
|
a = app('iTunes')
|
2009-06-10 13:54:24 +00:00
|
|
|
a.activate(timeout=0)
|
2009-06-01 09:55:11 +00:00
|
|
|
try:
|
2009-06-10 13:54:24 +00:00
|
|
|
[source] = [s for s in a.sources(timeout=0) if s.kind(timeout=0) == k.library]
|
|
|
|
[library] = source.library_playlists(timeout=0)
|
2009-06-01 09:55:11 +00:00
|
|
|
except ValueError:
|
|
|
|
logging.warning('Some unexpected iTunes configuration encountered')
|
|
|
|
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)
|
2009-06-10 13:54:24 +00:00
|
|
|
if track.location(timeout=0) == k.missing_value:
|
2009-06-01 09:55:11 +00:00
|
|
|
self.dead_tracks.append(track)
|
|
|
|
logging.info('Found %d dead tracks' % len(self.dead_tracks))
|
|
|
|
|
2011-09-21 17:55:26 +00:00
|
|
|
self.view.start_job(JobType.ScanDeadTracks, do)
|
2009-06-01 09:55:11 +00:00
|
|
|
|
2012-01-16 15:30:45 +00:00
|
|
|
class PyDupeGuru(PyDupeGuruBase):
|
|
|
|
def __init__(self):
|
|
|
|
self._init(DupeGuruME)
|
|
|
|
|
|
|
|
def removeDeadTracks(self):
|
|
|
|
self.model.remove_dead_tracks()
|
|
|
|
|
|
|
|
def scanDeadTracks(self):
|
|
|
|
self.model.scan_dead_tracks()
|
|
|
|
|
|
|
|
#---Information
|
|
|
|
def deadTrackCount(self) -> int:
|
|
|
|
return len(self.model.dead_tracks)
|
|
|
|
|
|
|
|
#---Properties
|
|
|
|
def setMinMatchPercentage_(self, percentage: int):
|
|
|
|
self.model.scanner.min_match_percentage = percentage
|
|
|
|
|
|
|
|
def setScanType_(self, scan_type: int):
|
|
|
|
try:
|
|
|
|
self.model.scanner.scan_type = [
|
|
|
|
ScanType.Filename,
|
|
|
|
ScanType.Fields,
|
|
|
|
ScanType.FieldsNoOrder,
|
|
|
|
ScanType.Tag,
|
|
|
|
ScanType.Contents,
|
|
|
|
ScanType.ContentsAudio,
|
|
|
|
][scan_type]
|
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def setWordWeighting_(self, words_are_weighted: bool):
|
|
|
|
self.model.scanner.word_weighting = words_are_weighted
|
|
|
|
|
|
|
|
def setMatchSimilarWords_(self, match_similar_words: bool):
|
|
|
|
self.model.scanner.match_similar_words = match_similar_words
|
|
|
|
|
|
|
|
def enable_scanForTag_(self, enable: bool, scan_tag: str):
|
|
|
|
if enable:
|
|
|
|
self.model.scanner.scanned_tags.add(scan_tag)
|
|
|
|
else:
|
|
|
|
self.model.scanner.scanned_tags.discard(scan_tag)
|