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 , TypeVar
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,43 @@ 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
+ T = TypeVar ("T" )
118
+
119
+
120
+ def _take (
121
+ iter : Iterable [T ],
122
+ num : int ,
123
+ ) -> list [T ]:
110
124
"""Return a list containing the first `num` values in `iter` (or
111
125
fewer, if the iterable ends early).
112
126
"""
113
- out = []
114
- for val in iter :
115
- out .append (val )
116
- num -= 1
117
- if num <= 0 :
118
- break
119
- return out
127
+ return list (islice (iter , num ))
120
128
121
129
122
- def _take_time (iter , secs , album ):
130
+ def _take_time (
131
+ iter : Iterable [Item | Album ],
132
+ secs : float ,
133
+ ) -> list [Item | Album ]:
123
134
"""Return a list containing the first values in `iter`, which should
124
135
be Item or Album objects, that add up to the given amount of time in
125
136
seconds.
126
137
"""
127
- out = []
138
+ out : list [ Item | Album ] = []
128
139
total_time = 0.0
129
140
for obj in iter :
130
- length = _length (obj , album )
141
+ length = _length (obj )
131
142
if total_time + length <= secs :
132
143
out .append (obj )
133
144
total_time += length
134
145
return out
135
146
136
147
137
148
def random_objs (
138
- objs , album , number = 1 , time = None , equal_chance = False , random_gen = None
149
+ objs : Sequence [Item | Album ],
150
+ number = 1 ,
151
+ time : float | None = None ,
152
+ equal_chance : bool = False ,
153
+ random_gen : random .Random | None = None ,
139
154
):
140
155
"""Get a random subset of the provided `objs`.
141
156
@@ -152,11 +167,11 @@ def random_objs(
152
167
if equal_chance :
153
168
perm = _equal_chance_permutation (objs )
154
169
else :
155
- perm = objs
156
- rand .shuffle (perm ) # N.B. This shuffles the original list.
170
+ perm = list ( objs )
171
+ rand .shuffle (perm )
157
172
158
173
# Select objects by time our count.
159
174
if time :
160
- return _take_time (perm , time * 60 , album )
175
+ return _take_time (perm , time * 60 )
161
176
else :
162
177
return _take (perm , number )
0 commit comments