async def schedule(loop, playlist): while calc_scheduled_minutes(playlist) < datetime.timedelta( minutes=config.SCHEDULED_PLAYLIST_MINUES): track = Session.query(Track).order_by(sa.func.random()).first() scheduled_track = playlist.append(track) Session.add(scheduled_track) Session.commit() log.info("scheduled %s at %s", track.description, scheduled_track.start_time.isoformat()) now_playing(loop, scheduled_track)
async def load_playlist(url, f): log.info("loading playlist from %s", url) playlist = (await f.read()).decode("utf-8").splitlines() for item_url in playlist: if not Session.query(SeenUrl).filter_by(url=item_url).first(): queue_url(item_url)
async def load_track(loop, url, body): cache = Cache() log.info("preparing track %s", url) with tempfile.NamedTemporaryFile(delete=False, dir=config.TMP_DIR) as f: digester = hashlib.sha256() while True: chunk = await body.read(config.CHUNK_SIZE) if not chunk: break digester.update(chunk) f.write(chunk) f.close() digest = digester.hexdigest() track = Session.query(Track).filter_by(digest=digest).first() if not track: track = Track(digest=digest) Session.add(track) if not track.metatada: metadata = await scrape_metadata(track, f.name) if metadata: Session.add_all(metadata) track.metadata_items.extend(metadata) tmp_path = os.path.join(config.TMP_DIR, f.name) os.makedirs(cache.get_cache_dir(track), exist_ok=True) cache_path = cache.get_cache_path(track) os.rename(tmp_path, cache_path) await segment_track(loop, cache_path, cache.get_segment_format_path(track), config.TARGET_DURATION) os.remove(cache_path) seen = Session.query(SeenUrl).filter_by(url=url, track=track).first() if not seen: seen = SeenUrl(url=url, track=track) Session.add(seen) Session.commit()
async def handle_playlist(request): playlist_id = request.match_info["playlist_id"] playlist = Session.query(Playlist).filter_by(id=playlist_id).first() renderer = M3U8Renderer("http://localhost:8080") filename = playlist.name + ".m3u8" headers = { "Content-Type": MPEGURL_MIME, "Content-Disposition": "inline; filename=\"{}\"".format(filename), } return web.Response(body=renderer.render( playlist, datetime.datetime.utcnow()).encode("utf-8"), headers=headers)
async def schedule_all(loop): for playlist in Session.query(Playlist): await schedule(loop, playlist)
def current_playlists(loop): for playlist in Session.query(Playlist): for st in playlist.upcoming_schedule: log.info("upcoming %s at %s", st.track.description, st.start_time.isoformat()) now_playing(loop, st)
async def handle_segment(request): digest = request.match_info["digest"] segment_num = int(request.match_info["num"]) track = Session.query(Track).filter_by(digest=digest).one() segment_path = Cache().get_segment_path(track, segment_num) return web.FileResponse(segment_path)
async def handle_playlists(request): host = request.headers["Host"] cursor = Session.query(Playlist).order_by(Playlist.name) playlists = [project_playlist(pl, host) for pl in cursor] return ok(playlists=playlists)