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_authenticated
isTrue
. 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 Track
s, 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
Vote
s 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
Play
s 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 Note
s. 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.