Browse Source

FIX #1: --source-weights

source weights are meant to first of all pick a source, with the
defined weights. This option is unrelated to --random. In fact,
--random will switch from chronological order to random one.
--source-weights will, instead, pick only one of the sources given in
command line.

A typical example is for jingles: if you have a big number of jingles that
should run relatively rarely, and a small number of jingles that should
run often, then putting them all in the same directory isn't a good
idea. You'd better put them in two different dirs and use
--source-weights 1:2
boyska 6 years ago
parent
commit
1be085976e
1 changed files with 34 additions and 2 deletions
  1. 34 2
      feed

+ 34 - 2
feed

@@ -16,11 +16,31 @@ import urllib.request
 from urllib.parse import urlparse, unquote
 import posixpath
 import random
+from bisect import bisect
 
 from lxml import html
 import requests
 
 
+def weighted_choice(values, weights):
+    '''
+    random.choice with weights
+
+    weights must be integers greater than 0.
+
+    Their meaning is "relative", that is [1,2,3] is the same as [2,4,6]
+    '''
+    assert len(values) == len(weights)
+    total = 0
+    cum_weights = []
+    for w in weights:
+        total += w
+        cum_weights.append(total)
+    x = random.random() * total
+    i = bisect(cum_weights, x)
+    return values[i]
+
+
 class Audio(object):
     def __init__(self, url, durata=None):
         self.url = url
@@ -138,6 +158,8 @@ def get_parser():
                    help='Exclude any audio that is longer than MAXLEN seconds')
     p.add_argument('--random', default=False,
                    action='store_true', help='Pick randomly')
+    p.add_argument('--source-weights',
+                   help='Select only one "source" based on this weights')
     p.add_argument('--howmany', default=1, type=int,
                    help='If not specified, only 1 will be played')
     p.add_argument('--slotsize', help='Seconds between each audio', type=int)
@@ -173,13 +195,23 @@ def put(audio, copy=False):
 
 
 def main():
-    args = get_parser().parse_args()
+    parser = get_parser()
+    args = parser.parse_args()
     if not args.debug:
         logging.basicConfig(level=logging.WARNING)
     else:
         logging.basicConfig(level=logging.DEBUG)
+    sources = args.urls
+
+    if args.source_weights:
+        weights = tuple(map(int, args.source_weights.split(':')))
+        if len(weights) != len(sources):
+            parser.exit(status=2, message='Weight must be in the'
+                        ' same number as sources\n')
+        sources = [weighted_choice(sources, weights)]
+
     audios = []
-    for url in args.urls:
+    for url in sources:
         if url.startswith('http:') or url.startswith('https:') \
            or os.path.isfile(url):
             # download the feed