Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mosaic plugin #2352

Closed
wants to merge 631 commits into from
Closed
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
631 commits
Select commit Hold shift + click to select a range
419d9a0
Remove an accidentally-committed config
sampsyo Apr 15, 2017
a2eb6fa
Merge pull request #2518 from jwilk/re.sub
sampsyo Apr 15, 2017
560d003
Merge pull request #2514 from MolarAmbiguity/master
sampsyo Apr 15, 2017
8e58a61
Remove one blank line
sampsyo Apr 15, 2017
346ecbc
Slightly more verbose config overlay description
sampsyo Apr 15, 2017
f7a5844
Change the error name to DBAccessError
Mary011196 Apr 16, 2017
0492741
Error check with if statemetnt
Mary011196 Apr 16, 2017
a99b7e9
Provided default value for export.
SpirosChadoulos Apr 16, 2017
8a99eea
Merge pull request #2509 from mattmurch/Issue549
sampsyo Apr 16, 2017
512031a
Revise changelog for #2509
sampsyo Apr 16, 2017
e756f98
Correcting the mistakes that Travis CI showed me
Mary011196 Apr 16, 2017
621427f
Reformat a docstring
sampsyo Apr 18, 2017
19e0958
Re-raise other errors
sampsyo Apr 18, 2017
906bd97
Hint about database access errors
sampsyo Apr 18, 2017
7eaaa99
Changelog entry for #2508
sampsyo Apr 18, 2017
ffcaf33
add -f argument to play command
tweitzel Apr 18, 2017
5361825
added 1 line before for loop
SpirosChadoulos Apr 19, 2017
7018307
deleted else
SpirosChadoulos Apr 19, 2017
3e9076b
deleted else
SpirosChadoulos Apr 19, 2017
de57602
fixed certain errors
SpirosChadoulos Apr 19, 2017
60318f1
fixed line length
SpirosChadoulos Apr 19, 2017
18c5128
more flake8 updates
discopatrick Apr 19, 2017
21c59bf
Merge pull request #2508 from Mary011196/master
sampsyo Apr 19, 2017
31c7330
Merge pull request #2517 from discopatrick/date-value-field-validation
sampsyo Apr 19, 2017
29b57fb
Changelog for #2517
sampsyo Apr 19, 2017
18127ce
Merge branch 'master' of github.com:beetbox/beets
sampsyo Apr 19, 2017
02aa619
rename --force to --yes in play plugin
tweitzel Apr 19, 2017
78f19db
Merge pull request #2521 from tweitzel/master
sampsyo Apr 19, 2017
9d42728
ftintitle: Clarify control flow
sampsyo Apr 19, 2017
fae8fcc
ftintitle: Clarify indexing
sampsyo Apr 19, 2017
ab7cc8f
Merge branch 'master' into date-value-field-validation-method
discopatrick Apr 20, 2017
713c00a
reverts order of precisions from broadest to narrowest
discopatrick Apr 20, 2017
85adbd1
gives variable the better name of ‘ordinal’
discopatrick Apr 20, 2017
4dbc413
consolidates the declaration and incrementing of `ordinal` into one line
discopatrick Apr 21, 2017
80f77ae
Merge pull request #2522 from discopatrick/date-value-field-validatio…
sampsyo Apr 21, 2017
7a3c786
command-output: Wire subproc stdin to /dev/null
Apr 22, 2017
7a08e4a
Changelog for 2524
Apr 22, 2017
b38f34b
command_output: insure py2/3 compat
Apr 22, 2017
5841752
Rename `InvalidQueryArgumentTypeError` to `InvalidQueryArgumentValueE…
discopatrick Apr 20, 2017
bd48559
Merge branch 'master' into rename-error
discopatrick Apr 22, 2017
63cd799
Raise the correct error type
discopatrick Apr 21, 2017
d24b373
Adjust indentation to pass flake8 tests
discopatrick Apr 22, 2017
95a868b
Don't hardcode errno constant
jwilk Apr 23, 2017
2c71092
Merge pull request #2526 from jwilk/errno
sampsyo Apr 24, 2017
68089ac
Merge pull request #2524 from beetbox/command-output-close-stdin
nathdwek Apr 24, 2017
61b8329
Add a date query precision of ‘hour’
discopatrick Apr 25, 2017
5f2c47e
Test further hour precision intervals
discopatrick Apr 25, 2017
ba324df
Add a date query precision of ‘minute’
discopatrick Apr 25, 2017
b8e1c56
Fix tests
discopatrick Apr 25, 2017
05f0072
Update docstring
discopatrick Apr 26, 2017
6a71504
Allow multiple date formats for each precision
discopatrick Apr 26, 2017
c3771f7
Allow hour precision queries to use space separator
discopatrick Apr 26, 2017
04e2975
Separate date formats onto individual lines
discopatrick Apr 26, 2017
c10eb8f
Keep docstring line <= 79 characters
discopatrick Apr 26, 2017
02bd19f
Allow minute precision queries to use space separator
discopatrick Apr 26, 2017
24890c7
Add a date query precision of ‘second’
discopatrick Apr 26, 2017
1ab913b
Test each valid datetime separator
discopatrick Apr 27, 2017
5a3b74f
Test an invalid datetime separator raises error
discopatrick Apr 27, 2017
6e6dd76
Remove space separator tests from test_x_precision_intervals tests
discopatrick Apr 27, 2017
50a2e37
Keep function names lowercase to pass flake8 tests
discopatrick Apr 27, 2017
c51ecd4
add composer_sort tag#
dosoe Apr 28, 2017
e3c3798
little indentation stuff
dosoe Apr 28, 2017
075e243
deleted one duplicate block
dosoe Apr 28, 2017
2a418a6
ASFStorageStyle corrected
dosoe Apr 28, 2017
d4ff82e
adding image stuff for composer_sort
dosoe Apr 28, 2017
4a17da8
requested changes: where there is no artist_sort, there is no need fo…
dosoe Apr 28, 2017
23f172d
if there is no artist_sort, there should not be a composer_sort.
dosoe Apr 28, 2017
ac06be1
Add flake8 check for blind excepts
jackwilsdon Apr 26, 2016
bb5629e
Remove untyped except statements
Apr 25, 2016
287e077
Remove blind excepts from bluelet.py
Apr 28, 2016
f622e42
Replace blind excepts with generic Exception excepts in tests
jackwilsdon Apr 28, 2016
813b078
added composer_sort on test_mediafile.py since there is artist_sort
dosoe Apr 29, 2017
e9c3d69
Fix a typo
sampsyo Apr 29, 2017
dd7b129
Turn off unnecessary execute bit
sampsyo Apr 29, 2017
8e78cfd
Always pass unicode to print_
sampsyo Apr 30, 2017
bab99f5
Added a test for the new export feature
SpirosChadoulos Apr 30, 2017
a881922
ExportTest correction
SpirosChadoulos Apr 30, 2017
2bf58a6
Decode string with Unicode escape
Kraymer Apr 30, 2017
1c0b795
Refactor date-finding loop into an inner function
discopatrick May 1, 2017
84febb1
Merge pull request #2523 from discopatrick/rename-error
sampsyo May 1, 2017
a165d6c
Fix MusiXmatch text extraction markers
Kraymer May 1, 2017
f8862ac
Sort imports
Kraymer May 1, 2017
4e0527f
Docstrings style
Kraymer May 1, 2017
a85dcd8
Store whole expected lyrics, not just keywords, but randomized
Kraymer May 1, 2017
d88cabc
Divide LyricsGooglePluginTest into two classes.
Kraymer May 1, 2017
fa9262d
Disable tests that do real requests to lyrics sites by default.
Kraymer May 1, 2017
3e3ad69
Fix PEP8
Kraymer May 2, 2017
11eb90c
Fix PEP8
Kraymer May 2, 2017
3e38a33
Fix PEP8
Kraymer May 2, 2017
07af27e
Lyrics are last paragraph with class 'mxm-lyrics__content'
Kraymer May 2, 2017
7dab9f3
Restore beets module import
Kraymer May 2, 2017
b3fbdba
Fix flake8
Kraymer May 2, 2017
f53ab80
Add indent
Kraymer May 2, 2017
49e548b
Remove mention of python-itunes
owcz May 3, 2017
471d46d
web: __init__: _rep: Filter all bytes for serializer
ocelotsloth May 3, 2017
8b4b64d
Changelog for #2540
owcz May 3, 2017
8f32bfe
Reactivate test of LyricsCom and MusiXmatch sources
Kraymer May 3, 2017
fc6b65d
Merge pull request #2538 from Kraymer/lyrics-test
Kraymer May 3, 2017
ce48578
Merge pull request #2540 from owcz/patch-1
Kraymer May 3, 2017
e7ea7ab
Update fetchart.rst
Kraymer May 3, 2017
9394e0a
web: __init__: _rep: change to base64 encoding
ocelotsloth May 3, 2017
22f07b9
web: __init__: _rep: Make the looping more pythonic
ocelotsloth May 3, 2017
409f070
Remove lyrics.com source
Kraymer May 3, 2017
6fa1651
Update changelog
Kraymer May 3, 2017
908b8dc
Merge pull request #2542 from ocelotsloth/2532-web-serializer-bytes
sampsyo May 4, 2017
b57c49d
Add a period to a comment, simplify one expression
sampsyo May 4, 2017
376c31a
Changelog for #2542, which fixes #2532
sampsyo May 4, 2017
faf8be0
Merge pull request #2549 from Kraymer/drop-lyrics-com
sampsyo May 4, 2017
6ab7ad2
Improve changelog for #2549, which fixes #2548
sampsyo May 4, 2017
fc560ac
Rearrange changelog for feature removal
sampsyo May 4, 2017
90c30d8
Added an if album: statement
SpirosChadoulos May 4, 2017
167ae91
Changes at line 1486
SpirosChadoulos May 4, 2017
09ea544
Recompress png file (#2552)
ibmibmibm May 5, 2017
f5b23ff
Replaced all AssertNotExists with AssertExists
SpirosChadoulos May 6, 2017
0dc948d
Made sure that the destination directory will exist
SpirosChadoulos May 11, 2017
51835e7
Minor fixes to move tests
SpirosChadoulos May 11, 2017
c4ef23d
Minor Flake fixes
SpirosChadoulos May 11, 2017
e444143
Corrected line length
dosoe May 12, 2017
8f62e8b
Requested changes done
SpirosChadoulos May 12, 2017
169cf59
Fixed bool variable error
SpirosChadoulos May 12, 2017
7c91989
Minor flake fixes
SpirosChadoulos May 12, 2017
0cb643f
Merge pull request #2529 from dosoe/master
sampsyo May 12, 2017
9ccaad2
Undo some noisy whitespace changes
sampsyo May 12, 2017
5eca518
Changelog for #2529, which fixes #2519
sampsyo May 12, 2017
d0522d8
Merge branch 'master' of github.com:beetbox/beets
sampsyo May 12, 2017
3c852d3
docs
SpirosChadoulos May 13, 2017
9840964
Fix #2562: avoid crash with newlines in templates
sampsyo May 16, 2017
060041a
Load YAML as binary data
sampsyo May 17, 2017
35dd6fd
Changelog for #2566
sampsyo May 17, 2017
9fe171c
properly safe cast unicode as int
autrimpo May 17, 2017
ddfe442
r128 gain tags in mediafile test
autrimpo May 17, 2017
2685f13
replaygain: support r128
autrimpo May 13, 2017
8168a88
update replaygain docs with info about r128
autrimpo May 17, 2017
0148070
Merge pull request #2566 from beetbox/yaml-encoding
sampsyo May 17, 2017
a93414d
Document gapless mp3 encoding.
smlx May 25, 2017
348e044
Remove absolute paths from sample script.
smlx May 25, 2017
1da972f
implemented `set_field` cli parsing
bartkl May 30, 2017
569098a
store_dict parser action now stores unicode, and implementend set_fie…
bartkl May 30, 2017
91722ae
added documentation
bartkl May 30, 2017
b5a8891
implemented error handling for invalid, non-key/value cli argumnets
bartkl May 31, 2017
fbb868e
Merge branch 'master' into query-datetime-parser
discopatrick Jun 1, 2017
c648781
finished tests for set_fields on importer
bartkl Jun 1, 2017
e1101d4
Update assertion with correct error name
discopatrick Jun 1, 2017
95eeec9
Add docs for datetime queries
discopatrick Jun 1, 2017
ee46a51
Don't crash if non-canonical genre and prefer_specific: yes.
Jun 2, 2017
a43f5fd
Remove unnecessary test setup parameter.
Jun 2, 2017
0e7a0a6
Fix excessive line length.
Jun 2, 2017
f6830b4
Here, flake8, be happy.
Jun 2, 2017
b1d8321
Add Google Music plugin
tigranl Dec 15, 2016
291b287
Add a test for a non-range date query
discopatrick Jun 5, 2017
a559e6e
Edit the changelog for release
sampsyo Jun 10, 2017
9727ca7
Add date to the changelog
sampsyo Jun 10, 2017
8842bd3
Version bump: 1.4.5
sampsyo Jun 10, 2017
29d6c27
Fix some spurious whitespace changes
sampsyo Jun 11, 2017
b25eb87
Remove unnecessary output capture
sampsyo Jun 11, 2017
2315287
Simplify implementation of export behavior
sampsyo Jun 11, 2017
714560a
Fix parameter order and binding
sampsyo Jun 11, 2017
730c84e
Correct tests for export mode
sampsyo Jun 11, 2017
ca4f96e
Consolidate export tests into MoveTest
sampsyo Jun 11, 2017
0e47095
Merge pull request #2560 from autrimpo/r128
sampsyo Jun 11, 2017
7cacae5
Changelog for #2560 (fixes #2557)
sampsyo Jun 11, 2017
61fa3ee
Merge pull request #2576 from smlx/gapless-mp3
sampsyo Jun 11, 2017
f6dc981
Edit docs from #2576 for brevity
sampsyo Jun 11, 2017
15a7dfc
Merge pull request #2583 from yacoob/master
sampsyo Jun 11, 2017
1af3729
Changelog for #2583
sampsyo Jun 11, 2017
290162a
Merge pull request #2294 from anshuman73/master
sampsyo Jun 11, 2017
f4d3368
Some more clarity in comments for #2294
sampsyo Jun 11, 2017
389aed8
Merge pull request #2528 from discopatrick/query-datetime-parser
sampsyo Jun 11, 2017
d645c03
Changelog for #2528 (fixes #2506)
sampsyo Jun 11, 2017
0a73148
Slight refinements to time query docs
sampsyo Jun 11, 2017
dfde9ce
Merge pull request #2510 from SpirosChadoulos/master
sampsyo Jun 11, 2017
f65653a
Changelog for #2510 (fixes #435)
sampsyo Jun 11, 2017
28ba733
Add custom exception and mark fields as redacted.
tigranl Jun 11, 2017
06f86c8
PEP8
tigranl Jun 11, 2017
52d5d23
refactoring according to feedback in pull request
bartkl Jun 12, 2017
53d0421
added docstring for set_fields methods
bartkl Jun 12, 2017
2465898
refactoring according to suggestions in pull request
bartkl Jun 12, 2017
8555481
Update index.rst
tigranl Jun 12, 2017
2d7962c
Update toctree
tigranl Jun 12, 2017
762f9ca
revised to fix flake8 warnings
bartkl Jun 13, 2017
2eb4e3d
Merge branch 'master' into master
bartkl Jun 13, 2017
e0ce507
Merge pull request #2581 from bartkl/master
sampsyo Jun 13, 2017
719b699
Teensy whitespace fix
sampsyo Jun 13, 2017
3f68445
Move changelog entry to the right position
sampsyo Jun 13, 2017
71d6dc3
Docs refinements for #2581
sampsyo Jun 13, 2017
4563e3b
Merge pull request #2586 from tigranl/gmusic
sampsyo Jun 14, 2017
1f2b8ce
Tiny code and docs fixes for gmusic (#2586)
sampsyo Jun 14, 2017
97cedce
Changelog for #2586 (fixes #2553)
sampsyo Jun 14, 2017
ace5656
Complete set of __future__ imports
sampsyo Jun 14, 2017
d9c8f97
ReST syntax fix
sampsyo Jun 14, 2017
6664b65
Merge branch 'relativedate'
euri10 Jun 15, 2017
92c118f
Corrected some flake8 errors
euri10 Jun 15, 2017
527d0a8
Corrected some flake8 errors
euri10 Jun 15, 2017
ae3f9bf
Corrected some flake8 errors, overindentation and pycharm reformat
euri10 Jun 15, 2017
bc8a8ec
fix /issues/2592: web: Use Unicode paths to send files on Windows und…
Jun 15, 2017
cafbb24
fixed failing test - line too long
Jun 15, 2017
f36c70c
do not quote the value in xml, use quoteattr to add quotes as needed
Jun 15, 2017
338d471
Merge pull request #2593 from robot3498712/develop
sampsyo Jun 15, 2017
c840fea
Changelog for #2593
sampsyo Jun 15, 2017
009c6a4
Slightly clearer layout for #2593, and comments
sampsyo Jun 15, 2017
2144882
Correct some PEP8 post-docstring whitespace
sampsyo Jun 15, 2017
6f97787
Merge branch 'master' into euri10-master
sampsyo Jun 15, 2017
949d7fb
More docstring whitespace
sampsyo Jun 15, 2017
26940b6
Merge branch 'master' into relativedate
sampsyo Jun 15, 2017
8a6c8cd
Simplify the docs a bit for relative dates
sampsyo Jun 15, 2017
130c581
Some formatting cleanup for relative dates
sampsyo Jun 15, 2017
8ba0060
Wrap a long line
sampsyo Jun 16, 2017
f2b6801
Merge pull request #2596 from aranc23/metasync-fixes
sampsyo Jun 16, 2017
63692ff
Changelog for #2596 (fixes #2595)
sampsyo Jun 16, 2017
01cf0d0
Merge remote-tracking branch 'upstream/master'
euri10 Jun 16, 2017
93f064f
Renamed relative to relative_units
euri10 Jun 16, 2017
eaae3fb
Merge branch 'relativedate'
euri10 Jun 16, 2017
690ed73
Move the relative date docs downward
sampsyo Jun 16, 2017
b1b4272
Refinements to the relative date docs
sampsyo Jun 16, 2017
a52d3d5
Changelog for relative dates (#2418, #2598)
sampsyo Jun 16, 2017
d31a483
Merge pull request #2598 from beetbox/relativedate
sampsyo Jun 16, 2017
732f017
Expand error message for FileTypeError (#2599)
sampsyo Jun 17, 2017
d210645
Fix path in read errors while writing (#2599)
sampsyo Jun 17, 2017
2cd3e13
Spruce up changelog for release
sampsyo Jun 20, 2017
4917bd3
Add date to changelog
sampsyo Jun 20, 2017
7e8056b
Version bump: 1.4.6
sampsyo Jun 20, 2017
b575a1e
Always use specific null values for fixed fields
sampsyo Jun 20, 2017
2a9be17
Fix some brittle query tests
sampsyo Jun 20, 2017
41bd6f9
Explicitly let artpath be missing
sampsyo Jun 20, 2017
8085d13
Fix ipfs test to sort items in order
sampsyo Jun 20, 2017
336fdba
Musical key field may be None
sampsyo Jun 20, 2017
5ca43c3
Merge pull request #2605 from beetbox/fixednone
sampsyo Jun 21, 2017
6185c6a
Changelog for #2605
sampsyo Jun 21, 2017
70a2ad3
fixes issue #2615
autrimpo Jul 4, 2017
774fa62
Merge pull request #2623 from autrimpo/r128-#2615
sampsyo Jul 7, 2017
e742f86
Changelog for #2623 (fixes #2615)
sampsyo Jul 7, 2017
a983ea2
Merge branch 'Mosaicplugin'
Jul 14, 2017
887cf4e
pull master-branch and put mosaic plugin in own directory
Jul 14, 2017
0984b83
Ci build failed
Jul 14, 2017
a34814b
pep8 error
Jul 14, 2017
a613f92
try to fix the CI-Build error
Jul 14, 2017
55ccf13
Fixing image creation if cover is not present
Jul 15, 2017
7236ba9
Introduce unit test for mosaic
Jul 15, 2017
b237799
First unittest
Jul 15, 2017
fef8044
pep8 errors
Jul 15, 2017
fd4892b
Load of font
Jul 15, 2017
a779bb2
pep8 bug in test
Jul 15, 2017
252aa40
Remove font from plugin folder
Jul 15, 2017
644a0a3
Second
Jul 17, 2017
7a90a88
pep8 failure
Jul 17, 2017
ae1d7e7
remove own folder, bugfix alpha watermark option
Jul 18, 2017
0345985
fonturl configurable
Jul 18, 2017
0f8888e
missing space in operation
Jul 18, 2017
35dfcc1
Update of doc because of new option font, update of dependencies to r…
Jul 19, 2017
7fef4e2
Code documentation
Jul 19, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 249 additions & 0 deletions beetsplug/mosaic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
# This file is part of beets.
# Copyright 2015-2016, Ohm Patel.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Allows beets to create a mosaic from covers."""
from __future__ import division, absolute_import, print_function

import os.path

from beets.plugins import BeetsPlugin
from beets import ui

from PIL import Image
import math
from parse import *
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's usually best to avoid "star imports," which make it difficult to tell where names come from.


# MOSAICFONT = os.path.join(os.path.dirname(__file__), 'FreeSans.ttf')


class MosaicCoverArtPlugin(BeetsPlugin):
col_size = 4

def __init__(self):
super(MosaicCoverArtPlugin, self).__init__()

self.config.add({'geometry': '100x100+3+3',
'tile': '', # or e.g. x3 3x
'label': '',
'background': 'ffffff',
'mosaic': 'mosaic.png',
'show_mosaic': False,
'watermark': '',
'watermark_alpha': 0.4})

def commands(self):
cmd = ui.Subcommand('mosaic', help=u"create mosaic from coverart")

cmd.parser.add_option(
u'-m', u'--mosaic', dest='mosaic', metavar='FILE',
action='store',
help=u'save final mosaic picture as FILE'
)

cmd.parser.add_option(
u'-w', u'--watermark', dest='watermark',
action='store', metavar='FILE',
help=u'add FILE for a picture to blend over mosaic'
)

cmd.parser.add_option(
u'-a', u'--alpha', dest='watermark_alpha',
action='store', metavar='ALPHA',
help=u'ALPHA value for blending'
)
cmd.parser.add_option(
u'-c', u'--color', dest='background',
action='store', metavar='HEXCOLOR',
help=u'background color as HEXCOLOR'
)

cmd.parser.add_option(
u'-g', u'--geometry', dest='geometry',
action='store', metavar='GEOMETRY',
help=u'define geometry as <width>x<height>+<marginx>+<marginy>'
)

def func(lib, opts, args):
self.config.set_args(opts)

if self.config['mosaic']:
mosaic = opts.mosaic or self.config['mosaic'].get(str)
else:
mosaic = opts.mosaic

self._log.debug(u'Mosaic: {}', mosaic)

if self.config['watermark']:
watermark = opts.watermark or self.config['watermark'].get(str)
else:
watermark = opts.watermark

watermark_alpha = float(opts.watermark_alpha) or self.config[
'watermark_alpha'].get(float)

if self.config['background']:
background = opts.background or self.config[
'background'].get(str)
else:
background = opts.background

if self.config['geometry']:
geometry = opts.geometry or self.config[
'geometry'].get(str)
else:
geometry = opts.background
albums = lib.albums(ui.decargs(args))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you've already used self.config.set_args, you don't need all these if/else blocks for fallbacks. For example, this suffices just fine:

geometry = self.config['geometry'].get(str)

In fact, this is probably what you want:

geometry = self.config['geometry'].as_str()

No need to test whether the value is present; just use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, you don't even need to pass around stuff like geometry as a parameter—the code that needs it can just use self.config['geometry'].as_str() right there.


self._generate_montage(lib,
albums,
mosaic,
watermark,
background,
watermark_alpha,
geometry)

cmd.func = func
return [cmd]

def _generate_montage(self, lib, albums,
fn_mosaic, fn_watermark,
background, watermark_alpha, geometry):

parsestr = "{cellwidth:d}x{cellheight:d}"
parsestr += "+{cellmarginx:d}+{cellmarginy:d}"

geo = parse(parsestr, geometry)

covers = []

for album in albums:

if album.artpath and os.path.exists(album.artpath):
self._log.debug(u'{}', album.artpath)
covers.append(album.artpath)
else:
covers.append("||" + album.albumartist + "\n" + album.album)
self._log.debug(u'#{} has no album?#', album)

sqrtnum = int(math.sqrt(len(covers)))

tail = len(covers) - (sqrtnum * sqrtnum)

rows = cols = sqrtnum

if tail >= cols:
cols += 1

tail = len(covers) - (cols * sqrtnum)

if tail > 0:
rows += 1

self._log.debug(u'Cells: {}x{}', cols, rows)

mosaic_size_width = geo['cellmarginx'] + (cols * (geo['cellwidth'] +
geo['cellmarginx']))

mosaic_size_height = geo['cellmarginy'] + (rows *
(geo['cellheight'] +
geo['cellmarginy']))

self._log.debug(u'Mosaic size: {}x{}',
mosaic_size_width, mosaic_size_height)

montage = Image.new('RGB', (mosaic_size_width, mosaic_size_height),
tuple(int(background[i:i + 2], 16)
for i in (0, 2, 4)))

size = int(geo['cellwidth']), int(geo['cellheight'])
offset_x = int(geo['cellmarginx'])
offset_y = int(geo['cellmarginy'])
colcounter = 0

# fnt = ImageFont.truetype(MOSAICFONT, 12)

for cover in covers:

try:
if '||' in cover:

im = Image.new('RGB', size,
tuple(int(background[i:i + 2], 16)
for i in (0, 2, 4)))
# d = ImageDraw.Draw(im)
# d.multiline_text((10, 10), cover[2:],
# fill=(0, 0, 0), font=fnt, anchor=None,
# spacing=0, align="left")

else:
im = Image.open(cover)
im.thumbnail(size, Image.ANTIALIAS)

self._log.debug(u'Paste into mosaic: {} - {}x{}',
cover, offset_x, offset_y)
montage.paste(im, (offset_x, offset_y))

colcounter += 1
if colcounter >= cols:
offset_y += geo['cellwidth'] + geo['cellmarginy']
offset_x = geo['cellmarginx']
colcounter = 0
else:
offset_x += geo['cellwidth'] + geo['cellmarginx']

im.close()
except IOError:
self._log.error(u'Problem with {}', cover)

if fn_watermark:
foreground = Image.open(fn_watermark)
m_width, m_height = montage.size
f_width, f_height = foreground.size

if f_width > f_height:
d = f_width / 2 - (f_height / 2)
e = f_width / 2 + (f_height / 2)
box = (d, 0, e, f_height)
nf = foreground.crop(box)
elif f_width < f_height:
d = f_height / 2 - (f_width / 2)
e = f_height / 2 + (f_width / 2)
box = (0, d, f_width, e)
nf = foreground.crop(box)
else:
nf = foreground

longer_side = max(montage.size)
horizontal_padding = (longer_side - montage.size[0]) / 2
vertical_padding = (longer_side - montage.size[1]) / 2
img5 = montage.crop(
(
-horizontal_padding,
-vertical_padding,
montage.size[0] + horizontal_padding,
montage.size[1] + vertical_padding
)
)

m_width, m_height = img5.size

nf2 = nf.resize(img5.size, Image.ANTIALIAS)
f_width, f_height = nf2.size

self._log.debug(u'Save montage to: {}:{}-{} {}:{}-{}',
img5.mode, m_width, m_height, nf.mode,
f_width, f_height)
Image.blend(img5, nf2, watermark_alpha).save(fn_mosaic)
else:
montage.save(fn_mosaic)
57 changes: 57 additions & 0 deletions docs/plugins/mosaic.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Mosaic Plugin
=====================

The ``mosaic`` plugin generates a montage of a mosiac from cover art.

To use the ``mosaic`` plugin, first enable it in your configuration (see
:ref:`using-plugins`). Then, install the `Pillow`_ library by typing::

pip install Pillow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this plugin also uses a library called parse, so you probably want to mention that here. (Or just use regular expressions instead.)


The plugin uses `Pillow`_ to manipulate album art and create the mosiac.

.. _pillow: http://pillow.readthedocs.io/en/latest/


By default the ``mosaic`` generates a mosaic, as mosaic.png in the current directory, of cover art out of the whole library .

You can customize the output mosaic, overlay and blend a image as watermark and use a alternative filename as result picture ::

-h, --help show this help message and exit
-m FILE, --mosaic=file save final mosaic picture as FILE
-w FILE, --watermark=FILE add FILE for a picture to blend over mosaic
-a ALPHA, --alpha=ALPHA ALPHA value for blending 0.0-1.0
-c HEXCOLOR, --color=HEXCOLOR background color as HEXCOLOR
-g GEOMETRY, --geometry=GEOMETRY Geometry defined as <width>x<height>+<marginx>+<marginy>

Examples
--------
Create mosaic from all Album cover art::

$ beet mosaic

Create mosaic from band Tool with a second picture as watermark::

$ beet mosaic -w c:/temp/tool.png -a 0.4 Tool

Create mosaic from every Album out of year 2012, use background color red::

$ beet mosaic -b ff0000 year:2012

Configuration
-------------

To configure the plugin, make a ``mosaic:`` section in your
configuration file. There is four option:

- **mosaic**: Use a different filename for the final mosaic picture,
Default: ``mosaic.png``.
- **watermark**: Use a picture to blend over the mosiac picture,
Default: ''None''.
- **alpha**: The factor as float, to blend the watermark over the mosaic. 0.0 - means no visible watermark. 1.0 - full visible watermark.
Default: ``0.4``
- **background**: The color of the background and the visible border of the mosaic as Hexcolor e.g. ffffff for white or 000000 as black
Default: ``ffffff``
- **geometry**: Define geometry of each cover defined as <width>x<height>+<marginx>+<marginy>
- Default: ``100x100+3+3``

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def build_manpages():
'thumbnails': ['pyxdg'] +
(['pathlib'] if (sys.version_info < (3, 4, 0)) else []),
'metasync': ['dbus-python'],
'mosaic': ['pillow','parse'],
},
# Non-Python/non-PyPI plugin dependencies:
# convert: ffmpeg
Expand Down