From 385768a69bdc7001ff3ea558f2a7448ca50bd143 Mon Sep 17 00:00:00 2001 From: hsoft Date: Fri, 23 Oct 2009 14:35:51 +0000 Subject: [PATCH] dgme qt: adjusted code to the hsfs move. --HG-- extra : convert_revision : svn%3Ac306627e-7827-47d3-bdf0-9a457c9553a1/trunk%40206 --- base/py/fs.py | 5 - base/py/scanner.py | 6 - base/py/tests/scanner_test.py | 12 -- me/py/__init__.py | 0 base/py/app_me_cocoa.py => me/py/app_cocoa.py | 14 +- base/py/data_me.py => me/py/data.py | 2 +- me/py/fs.py | 183 ++++++++++++++++++ me/py/scanner.py | 16 ++ me/py/tests/__init__.py | 0 me/py/tests/scanner_test.py | 33 ++++ me/qt/app.py | 8 +- 11 files changed, 243 insertions(+), 36 deletions(-) create mode 100644 me/py/__init__.py rename base/py/app_me_cocoa.py => me/py/app_cocoa.py (86%) rename base/py/data_me.py => me/py/data.py (97%) create mode 100644 me/py/fs.py create mode 100644 me/py/scanner.py create mode 100644 me/py/tests/__init__.py create mode 100644 me/py/tests/scanner_test.py diff --git a/base/py/fs.py b/base/py/fs.py index 93bc1d4d..1f01349f 100644 --- a/base/py/fs.py +++ b/base/py/fs.py @@ -110,11 +110,6 @@ class File(object): except Exception: pass - def _invalidate_info(self): - for attrname in self.INITIAL_INFO: - if attrname in self.__dict__: - delattr(self, attrname) - def _read_all_info(self, attrnames=None): """Cache all possible info. diff --git a/base/py/scanner.py b/base/py/scanner.py index 1a6b3389..3f999920 100644 --- a/base/py/scanner.py +++ b/base/py/scanner.py @@ -106,9 +106,3 @@ class Scanner(object): scanned_tags = set(['artist', 'title']) size_threshold = 0 word_weighting = False - -class ScannerME(Scanner): # Scanner for Music Edition - @staticmethod - def _key_func(dupe): - return (not dupe.is_ref, -dupe.bitrate, -dupe.size) - diff --git a/base/py/tests/scanner_test.py b/base/py/tests/scanner_test.py index 7ae50715..1ce0f8f7 100644 --- a/base/py/tests/scanner_test.py +++ b/base/py/tests/scanner_test.py @@ -436,15 +436,3 @@ def test_partial_group_match(): assert o2 in group assert o3 not in group eq_(s.discarded_file_count, 1) - - -#--- Scanner ME -def test_priorize_me(): - # in ScannerME, bitrate goes first (right after is_ref) in priorization - s = ScannerME() - o1, o2 = no('foo'), no('foo') - o1.bitrate = 1 - o2.bitrate = 2 - [group] = s.GetDupeGroups([o1, o2]) - assert group.ref is o2 - diff --git a/me/py/__init__.py b/me/py/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/base/py/app_me_cocoa.py b/me/py/app_cocoa.py similarity index 86% rename from base/py/app_me_cocoa.py rename to me/py/app_cocoa.py index d9850c2d..692f847f 100644 --- a/base/py/app_me_cocoa.py +++ b/me/py/app_cocoa.py @@ -7,29 +7,29 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/hs_license -import os.path as op import logging from appscript import app, k, CommandError import time from hsutil.cocoa import as_fetch -import hsfs.phys.music -import app_cocoa, data_me, scanner +from dupeguru.app_cocoa import JOBID2TITLE, DupeGuru as DupeGuruBase + +from . import data, scanner, fs JOB_REMOVE_DEAD_TRACKS = 'jobRemoveDeadTracks' JOB_SCAN_DEAD_TRACKS = 'jobScanDeadTracks' -app_cocoa.JOBID2TITLE.update({ +JOBID2TITLE.update({ JOB_REMOVE_DEAD_TRACKS: "Removing dead tracks from your iTunes Library", JOB_SCAN_DEAD_TRACKS: "Scanning the iTunes Library", }) -class DupeGuruME(app_cocoa.DupeGuru): +class DupeGuruME(DupeGuruBase): def __init__(self): - app_cocoa.DupeGuru.__init__(self, data_me, 'dupeGuru Music Edition', appid=1) + DupeGuruBase.__init__(self, data, 'dupeGuru Music Edition', appid=1) self.scanner = scanner.ScannerME() - self.directories.dirclass = hsfs.phys.music.Directory + self.directories.fileclasses = [fs.Mp3File, fs.Mp4File, fs.WmaFile, fs.OggFile, fs.FlacFile, fs.AiffFile] self.dead_tracks = [] def remove_dead_tracks(self): diff --git a/base/py/data_me.py b/me/py/data.py similarity index 97% rename from base/py/data_me.py rename to me/py/data.py index 4fc74069..ad9edda5 100644 --- a/base/py/data_me.py +++ b/me/py/data.py @@ -8,7 +8,7 @@ # http://www.hardcoded.net/licenses/hs_license from hsutil.str import format_time, FT_MINUTES, format_size -from .data import (format_path, format_timestamp, format_words, format_perc, +from dupeguru.data import (format_path, format_timestamp, format_words, format_perc, format_dupe_count, cmp_value) COLUMNS = [ diff --git a/me/py/fs.py b/me/py/fs.py new file mode 100644 index 00000000..0a47e709 --- /dev/null +++ b/me/py/fs.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +# Created By: Virgil Dupras +# Created On: 2009-10-23 +# $Id$ +# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) +# +# This software is licensed under the "HS" License as described in the "LICENSE" file, +# which should be included with this package. The terms are also available at +# http://www.hardcoded.net/licenses/hs_license + +from hsmedia import mpeg, wma, mp4, ogg, flac, aiff +from hsutil.str import get_file_ext +from dupeguru import fs + +TAG_FIELDS = ['audiosize', 'duration', 'bitrate', 'samplerate', 'title', 'artist', + 'album', 'genre', 'year', 'track', 'comment'] + +class MusicFile(fs.File): + INITIAL_INFO = fs.File.INITIAL_INFO.copy() + INITIAL_INFO.update({ + 'audiosize': 0, + 'bitrate' : 0, + 'duration' : 0, + 'samplerate':0, + 'artist' : '', + 'album' : '', + 'title' : '', + 'genre' : '', + 'comment' : '', + 'year' : '', + 'track' : 0, + }) + HANDLED_EXTS = set() + + @classmethod + def can_handle(cls, path): + if not fs.File.can_handle(path): + return False + return get_file_ext(path[-1]) in cls.HANDLED_EXTS + + +class Mp3File(MusicFile): + HANDLED_EXTS = set(['mp3']) + def _read_info(self, field): + if field == 'md5partial': + fileinfo = mpeg.Mpeg(unicode(self.path)) + self._md5partial_offset = fileinfo.audio_offset + self._md5partial_size = fileinfo.audio_size + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + fileinfo = mpeg.Mpeg(unicode(self.path)) + self.audiosize = fileinfo.audio_size + self.bitrate = fileinfo.bitrate + self.duration = fileinfo.duration + self.samplerate = fileinfo.sample_rate + i1 = fileinfo.id3v1 + # id3v1, even when non-existant, gives empty values. not id3v2. if id3v2 don't exist, + # just replace it with id3v1 + i2 = fileinfo.id3v2 + if not i2.exists: + i2 = i1 + self.artist = i2.artist or i1.artist + self.album = i2.album or i1.album + self.title = i2.title or i1.title + self.genre = i2.genre or i1.genre + self.comment = i2.comment or i1.comment + self.year = i2.year or i1.year + self.track = i2.track or i1.track + +class WmaFile(MusicFile): + HANDLED_EXTS = set(['wma']) + def _read_info(self, field): + if field == 'md5partial': + dec = wma.WMADecoder(unicode(self.path)) + self._md5partial_offset = dec.audio_offset + self._md5partial_size = dec.audio_size + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + dec = wma.WMADecoder(unicode(self.path)) + self.audiosize = dec.audio_size + self.bitrate = dec.bitrate + self.duration = dec.duration + self.samplerate = dec.sample_rate + self.artist = dec.artist + self.album = dec.album + self.title = dec.title + self.genre = dec.genre + self.comment = dec.comment + self.year = dec.year + self.track = dec.track + +class Mp4File(MusicFile): + HANDLED_EXTS = set(['m4a', 'm4p']) + def _read_info(self, field): + if field == 'md5partial': + dec = mp4.File(unicode(self.path)) + self._md5partial_offset = dec.audio_offset + self._md5partial_size = dec.audio_size + dec.close() + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + dec = mp4.File(unicode(self.path)) + self.audiosize = dec.audio_size + self.bitrate = dec.bitrate + self.duration = dec.duration + self.samplerate = dec.sample_rate + self.artist = dec.artist + self.album = dec.album + self.title = dec.title + self.genre = dec.genre + self.comment = dec.comment + self.year = dec.year + self.track = dec.track + dec.close() + +class OggFile(MusicFile): + HANDLED_EXTS = set(['ogg']) + def _read_info(self, field): + if field == 'md5partial': + dec = ogg.Vorbis(unicode(self.path)) + self._md5partial_offset = dec.audio_offset + self._md5partial_size = dec.audio_size + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + dec = ogg.Vorbis(unicode(self.path)) + self.audiosize = dec.audio_size + self.bitrate = dec.bitrate + self.duration = dec.duration + self.samplerate = dec.sample_rate + self.artist = dec.artist + self.album = dec.album + self.title = dec.title + self.genre = dec.genre + self.comment = dec.comment + self.year = dec.year + self.track = dec.track + +class FlacFile(MusicFile): + HANDLED_EXTS = set(['flac']) + def _read_info(self, field): + if field == 'md5partial': + dec = flac.FLAC(unicode(self.path)) + self._md5partial_offset = dec.audio_offset + self._md5partial_size = dec.audio_size + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + dec = flac.FLAC(unicode(self.path)) + self.audiosize = dec.audio_size + self.bitrate = dec.bitrate + self.duration = dec.duration + self.samplerate = dec.sample_rate + self.artist = dec.artist + self.album = dec.album + self.title = dec.title + self.genre = dec.genre + self.comment = dec.comment + self.year = dec.year + self.track = dec.track + +class AiffFile(MusicFile): + HANDLED_EXTS = set(['aif', 'aiff', 'aifc']) + def _read_info(self, field): + if field == 'md5partial': + dec = aiff.File(unicode(self.path)) + self._md5partial_offset = dec.audio_offset + self._md5partial_size = dec.audio_size + MusicFile._read_info(self, field) + if field in TAG_FIELDS: + dec = aiff.File(unicode(self.path)) + self.audiosize = dec.audio_size + self.bitrate = dec.bitrate + self.duration = dec.duration + self.samplerate = dec.sample_rate + tag = dec.tag + if tag is not None: + self.artist = tag.artist + self.album = tag.album + self.title = tag.title + self.genre = tag.genre + self.comment = tag.comment + self.year = tag.year + self.track = tag.track + diff --git a/me/py/scanner.py b/me/py/scanner.py new file mode 100644 index 00000000..7fce8427 --- /dev/null +++ b/me/py/scanner.py @@ -0,0 +1,16 @@ +# Created By: Virgil Dupras +# Created On: 2006/03/03 +# $Id$ +# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) +# +# This software is licensed under the "HS" License as described in the "LICENSE" file, +# which should be included with this package. The terms are also available at +# http://www.hardcoded.net/licenses/hs_license + +from dupeguru.scanner import Scanner as ScannerBase + +class ScannerME(ScannerBase): + @staticmethod + def _key_func(dupe): + return (not dupe.is_ref, -dupe.bitrate, -dupe.size) + diff --git a/me/py/tests/__init__.py b/me/py/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/me/py/tests/scanner_test.py b/me/py/tests/scanner_test.py new file mode 100644 index 00000000..6ab32a6d --- /dev/null +++ b/me/py/tests/scanner_test.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Created By: Virgil Dupras +# Created On: 2009-10-23 +# $Id$ +# Copyright 2009 Hardcoded Software (http://www.hardcoded.net) +# +# This software is licensed under the "HS" License as described in the "LICENSE" file, +# which should be included with this package. The terms are also available at +# http://www.hardcoded.net/licenses/hs_license + +from hsutil.path import Path + +from dupeguru.engine import getwords +from ..scanner import * + +class NamedObject(object): + def __init__(self, name="foobar", size=1): + self.name = name + self.size = size + self.path = Path('') + self.words = getwords(name) + + +no = NamedObject + +def test_priorize_me(): + # in ScannerME, bitrate goes first (right after is_ref) in priorization + s = ScannerME() + o1, o2 = no('foo'), no('foo') + o1.bitrate = 1 + o2.bitrate = 2 + [group] = s.GetDupeGroups([o1, o2]) + assert group.ref is o2 \ No newline at end of file diff --git a/me/qt/app.py b/me/qt/app.py index 87359304..5234c8fa 100644 --- a/me/qt/app.py +++ b/me/qt/app.py @@ -7,9 +7,7 @@ # which should be included with this package. The terms are also available at # http://www.hardcoded.net/licenses/hs_license -import hsfs.phys.music - -from dupeguru import data_me, scanner +from dupeguru_me import data, scanner, fs from base.app import DupeGuru as DupeGuruBase from details_dialog import DetailsDialog @@ -23,11 +21,11 @@ class DupeGuru(DupeGuruBase): DELTA_COLUMNS = frozenset([2, 3, 4, 5, 7, 8]) def __init__(self): - DupeGuruBase.__init__(self, data_me, appid=1) + DupeGuruBase.__init__(self, data, appid=1) def _setup(self): self.scanner = scanner.ScannerME() - self.directories.dirclass = hsfs.phys.music.Directory + self.directories.fileclasses = [fs.Mp3File, fs.Mp4File, fs.WmaFile, fs.OggFile, fs.FlacFile, fs.AiffFile] DupeGuruBase._setup(self) def _update_options(self):