14
14
15
15
"""Get a random song or album from the library."""
16
16
17
+ from __future__ import annotations
18
+
17
19
import random
18
- from itertools import groupby
20
+ from itertools import groupby , islice
19
21
from operator import attrgetter
22
+ from typing import Iterable , Sequence
20
23
24
+ from beets .library import Album , Item
21
25
from beets .plugins import BeetsPlugin
22
26
from beets .ui import Subcommand , print_
23
27
@@ -69,15 +73,19 @@ def commands(self):
69
73
return [random_cmd ]
70
74
71
75
72
- def _length (obj , album ) :
76
+ def _length (obj : Item | Album ) -> float :
73
77
"""Get the duration of an item or album."""
74
- if album :
78
+ if isinstance ( obj , Album ) :
75
79
return sum (i .length for i in obj .items ())
76
80
else :
77
81
return obj .length
78
82
79
83
80
- def _equal_chance_permutation (objs , field = "albumartist" , random_gen = None ):
84
+ def _equal_chance_permutation (
85
+ objs : Sequence [Item | Album ],
86
+ field : str = "albumartist" ,
87
+ random_gen : random .Random | None = None ,
88
+ ) -> Iterable [Item | Album ]:
81
89
"""Generate (lazily) a permutation of the objects where every group
82
90
with equal values for `field` have an equal chance of appearing in
83
91
any given position.
@@ -86,7 +94,7 @@ def _equal_chance_permutation(objs, field="albumartist", random_gen=None):
86
94
87
95
# Group the objects by artist so we can sample from them.
88
96
key = attrgetter (field )
89
- objs . sort ( key = key )
97
+ objs = sorted ( objs , key = key )
90
98
objs_by_artists = {}
91
99
for artist , v in groupby (objs , key ):
92
100
objs_by_artists [artist ] = list (v )
@@ -106,36 +114,40 @@ def _equal_chance_permutation(objs, field="albumartist", random_gen=None):
106
114
del objs_by_artists [artist ]
107
115
108
116
109
- def _take (iter , num ):
117
+ def _take (
118
+ iter : Iterable ,
119
+ num : int ,
120
+ ) -> list :
110
121
"""Return a list containing the first `num` values in `iter` (or
111
122
fewer, if the iterable ends early).
112
123
"""
113
- out = []
114
- for val in iter :
115
- out .append (val )
116
- num -= 1
117
- if num <= 0 :
118
- break
119
- return out
124
+ return list (islice (iter , num ))
120
125
121
126
122
- def _take_time (iter , secs , album ):
127
+ def _take_time (
128
+ iter : Iterable [Item | Album ],
129
+ secs : float ,
130
+ ) -> list [Item | Album ]:
123
131
"""Return a list containing the first values in `iter`, which should
124
132
be Item or Album objects, that add up to the given amount of time in
125
133
seconds.
126
134
"""
127
- out = []
135
+ out : list [ Item | Album ] = []
128
136
total_time = 0.0
129
137
for obj in iter :
130
- length = _length (obj , album )
138
+ length = _length (obj )
131
139
if total_time + length <= secs :
132
140
out .append (obj )
133
141
total_time += length
134
142
return out
135
143
136
144
137
145
def random_objs (
138
- objs , album , number = 1 , time = None , equal_chance = False , random_gen = None
146
+ objs : Sequence [Item | Album ],
147
+ number = 1 ,
148
+ time : float | None = None ,
149
+ equal_chance : bool = False ,
150
+ random_gen : random .Random | None = None ,
139
151
):
140
152
"""Get a random subset of the provided `objs`.
141
153
@@ -152,11 +164,11 @@ def random_objs(
152
164
if equal_chance :
153
165
perm = _equal_chance_permutation (objs )
154
166
else :
155
- perm = objs
156
- rand .shuffle (perm ) # N.B. This shuffles the original list.
167
+ perm = list ( objs )
168
+ rand .shuffle (perm )
157
169
158
170
# Select objects by time our count.
159
171
if time :
160
- return _take_time (perm , time * 60 , album )
172
+ return _take_time (perm , time * 60 )
161
173
else :
162
174
return _take (perm , number )
0 commit comments