Core concepts of nkd.su¶
nkd.su is built with Django. Here are some pointers to key parts of the code.
Types of user¶
nkd.su has a few different ways of presenting itself, depending on who is looking at it. There are:
- Anonymous users
- People who aren’t signed in. The site is functionally read-only for them. 
- Normal users
- People signed in to an account, for whom - is_authenticatedis- True. They can request music to be played and they can choose how they are represented on the website.
Models¶
Show¶
Every week, there is a radio broadcast of Neko Desu. Each broadcast corresponds
to a Show in the nkd.su database. By default, these get
automatically created when necessary, but they can be
created manually or modified on the admin site for special occasions, like when the show
runs for longer than usual. The show creation logic is kind of horrible and
complicated, because it has to deal with daylight savings time. There are a
fair number of tests for it, which is reassuring, but I
don’t want to touch it again if I don’t have to.
Track¶
The library consists of Tracks, which are populated from an iTunes
library XML export that gets uploaded to LibraryUploadView and
processed by update_library(). During this process, some checks get run against the existing library, in the
hopes of catching simple errors.
A key property of a Track is its ‘eligibility’. This is communicated
in the UI via its background colour; eligible tracks have a light background,
and ineligible tracks have a dark background. This property is influenced by a
lot of things. See Track.ineligible() to learn more.
In addition to this, each user has their own eligibility criteria.
Specifically, eligible_for() exists to prevent people from requesting
things twice.
Vote¶
When someone wants a Track to be played on the upcoming (or
currently-airing) Show, they create a Vote for it.
Note
User-facing text should be careful about the word ‘Vote’. Neko Desu
is not a democracy, and nkd.su is not a polling website. Current consensus
is that you should refer to the first Vote filed for a
Track in a given Show as a ‘request’. It is appropriate
to call any subsequent Vote a vote, though. This distinction is
communicated in the UI by making the ‘request’ much more prominent than
follow-up ‘vote’s.
Despite this ambiguity in user-facing names, they should always be called
Votes in the code and in the database in order to avoid
confusion with Request, which is a representation of a user’s
request to get a song added or some metadata fixed. To avoid confusion, this
documentation will use Vote and Request explicitly.
There are three different base types of Vote, enumerated in
VoteKind. In addition, manual votes have a number
of subtypes, listed in MANUAL_VOTE_KINDS. We aim to present these as
equivalently as possible in the UI.
The VoteKind of a Vote is not stored explicitly in the
database. Instead, it is calculated based on what attributes are present in
Vote.vote_kind(). To make sure there are no conflicts,
Vote.clean() ensures that only the attributes appropriate for a given
VoteKind are present on any given Vote.
Staff tools¶
Staff users can do a lot more things than any other user. They can create
Plays to reflect what’s being played on air. They can
Shortlist or Discard tracks to help prepare a playlist for
the show. They can perform library updates. They
can add public or private Notes. They can force a track to be
ineligible by putting a Block in effect.
For now at least, the full breadth of these features is probably out of scope for this document. I am currently not sure how to write an introduction to the inner workings of something for an audience that has never even seen its intended functionality. I may expand on this in future, though.