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 is True. They can request music to be played and they can choose how they are represented on the website.

Elfs

Members of the Group named Elfs, who will pass the is_elf() check. These are people who deal with sourcing music and metadata for the library. They have access to library update requests from users.

Staff

The host of the show. Represented by is_staff being True.

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.