diff --git a/server/djrandom/frontend/api_views.py b/server/djrandom/frontend/api_views.py
index 461724be4c9abb7ff8796c1bfcf1df69cf84510e..96f421a4f1f9d57e680f587e26fcf9178d125861 100644
--- a/server/djrandom/frontend/api_views.py
+++ b/server/djrandom/frontend/api_views.py
@@ -147,3 +147,11 @@ def more_like_these_json():
         results = svcs['searcher'].more_like_these(hashes)
     return jsonify(results=results)
 
+
+@app.route('/json/most_played', methods=['GET'])
+@require_auth
+def most_played_json():
+    most_played = [{'sha1': sha1, 'count': count}
+                   for sha1, count in PlayLog.most_played(20)]
+    return jsonify(results=most_played)
+
diff --git a/server/djrandom/model/mp3.py b/server/djrandom/model/mp3.py
index 783288687a90dd56e6a4a6a01405157c8fbe4a44..12a5b539d3364c812c325c54aecf73aba93d50fa 100644
--- a/server/djrandom/model/mp3.py
+++ b/server/djrandom/model/mp3.py
@@ -1,5 +1,5 @@
 from sqlalchemy import *
-from datetime import datetime
+from datetime import datetime, timedelta
 from djrandom.database import Base
 
 
@@ -47,6 +47,13 @@ class PlayLog(Base):
     stamp = Column(DateTime())
     prev = Column(Text())
 
+    @classmethod
+    def most_played(cls, n=10):
+        """Return the N most played songs."""
+        one_month_ago = datetime.now() - timedelta(30)
+        return Session.query(cls.sha1, func.count(cls.sha1).label('count')
+            ).group_by(cls.sha1).order_by('count desc').limit(n)
+
     @classmethod
     def generate_tuples(cls, n=2):
         """Yield all the transitions in the playlog.