Personal information
Name: Youzhi Liang
IRC nick: yuzie
Email: youzhi797@gmail.com
GitHub: YouzhiL (Youzhi) · GitHub
Time Zone:UTC-04:00
Overview
ListenBrainz helps users to track their music listening habits and analyzes their music taste. Such technology requires accurate user data to make the best decisions. However, at current state of the product, all the listens are collected in the UTC instead of their local timestamp, without taking DST in to consideration. Adding timezone preference for users and adding the time zone field in submitted listens will contribute to the analysis and thus provide better user experience. This project aims to add users’ timezone preference paired with their submitted listens.
Goals
- Users can set timezone preference in the setting page
- Design and implement an appropriate setting table which contains the user timezone preference, this table can be reused to store more user preferences.
- Design a React UI for the settings page so that users can set and edit their timezone in the setting page.
- Add an API endpoint to fetch/set user timezone.
- Users can add local timestamp field in the submit listens
- Add local timestamp in submission json of new listens
- validate and test the new field and modify the functions of inserting and fetching listens regarding the new field
Ideas
Currently, all the timezone-sensitive data are stored in UTC timezone, which is a good practice, because this avoid possible inconsistency if stored in user timezone or server timezone. So the basic idea is to store dates in UTC and how we query and display it to users varies in different cases.
- For any existing listens that have no timezones and user has a preference for timezone, show it in user selected timezone. If user does not have a preference for timezone, use the default.
- For future listens, if the submission does have a local timestamp, show it in the user selected timezone. If user does not have a preference for timezone, use the default.
- For future listens, if the submission has a local timestamp, show it in that timestamp.
Implementations
Task1: Users can set Timezone Preference in the setting page
database
For users to edit their preferences, we will create a new table user_setting
in our database. We store user timezone and other preferences in this table. We choose to store the timezone name instead of the offset because the offset can change for daylight savings. PostgreSQL supports identifying IANA timezone identifier.
CREATE TABLE "user_setting" (
id SERIAL,
user_id INTEGER NOT NULL,
zone_name TEXT NOT NULL CHECK (now() AT TIME ZONE zone_name IS NOT NULL)
)
now() AT TIME ZONE zone_name IS NOT NULL
will check if the zone_name
can be recognized by PostgreSQL. If not, it will throw an error timezone not recognized
, which can be catched by SQLAlchemy at the endpoint. Since we provides a dropbox for the users to select the timezone in frontend, which already limit the options to what PG can recognize, this validation will serve as a backup.
UI Mock-up
-
Add a Reset Timezone UI module in the general setting page.
-
After clicking the button”Reset Timezone” in the general setting page, users will be routed to a Reset Timezone page. This page includes a dropdown list, which contains all world timezones that PostgreSQL supports(perhaps part of all the 589 timezones).
API endpint
@profile_bp.route("/reset_time_zone/", methods=["GET", "POST"])
@login_required
def reset_time_zone():
if request.method == 'POST':
time_zone = request.form.get('time_zone')
try:
update_user_timezone(current_user.id, time_zone)
flash.info('Successfully update the timezone for %s.' % current_user.musicbrainz_id)
return redirect(url_for('profile.info'))
except Exception:
# Handle exception
else:
#render template
This API design is based on the assumption that we directly add the timezone setting to the existing settings page. If we have a new setting page in the future to allow users editing more preferences. We can have a general setting API.
@profile_bp.route('/settings/', methods=["GET", "POST"])
@login_required
def user_settings():
if request.method == 'POST':
time_zone = request.form.get('time_zone')
other_preference = request.form.get('other_preference')
if time_zone:
try:
update_user_timezone(current_user.id, time_zone)
flash.info('Successfully update the timezone for %s.' % current_user.musicbrainz_id)
return redirect(url_for('setting'))
except Exception:
# Handle exception
elif other_preference:
# Update other preference
else:
#render template
In ListenBrainz/db, we can add a user_setting.py
for sql expression.
def update_timezone(user_id: int, zone_name:str):
with db.engine.connect() as connection:
try:
connection.execute(sqlalchemy.text("""
UPDATE "user_setting"
SET zone_name = :zone_name
WHERE user_id = :user_id
"""), {
"user_id": user_id,
"zone_name": zone_name,
})
except sqlalchemy.exc.ProgrammingError as err:
logger.error(err)
raise DatabaseException(
"Couldn't update user's timezone: %s" % str(err))
Task2: Users can add timezone field in the listens submission json
This part is a stretch from the initial project. The basic idea on how to deal with local listen_time in API can be referenced in [LB-642] Specify a field for "local time" for listens - MetaBrainz JIRA.
- We alter json format by adding timezone field to allow users submitting their local timestamps in an ISO8601 string. The format should be limited to one of following types:
YYYY-MM-DDTHH:MM:SS.ffffff+HH:MM[:SS[.ffffff]]
if microsecond is not 0
YYYY-MM-DDTHH:MM:SS+HH:MM[:SS[.ffffff]]
if microsecond is 0
A possible json example will be:
{
"listened_at": 1443521965,
"track_metadata": {
"additional_info": {
"listened_at_local": "2015-09-29T03:19:25-07:00",
"release_mbid": "bf9e91ea-8029-4a04-a26a-224e00a83266",
},
"artist_name": "Rick Astley",
"track_name": "Never Gonna Give You Up",
"release_name": "Whenever you need somebody"
}
}
- If
listened_at_local
is specified, thenlistened_at
will be ignored. When parsing json file in API endpoint, we convert it to python datetime object:
>>> listened_at_local = datetime.fromisoformat("2011-11-04T00:05:23+05:00")
>>> listened_at_local
datetime.datetime(2011, 11, 4, 0, 5, 23, tzinfo=datetime.timezone(datetime.timedelta(seconds=18000)))
- We can extract the timezone information from the datetime object and store it as a separate row in database.
>>> listened_at_local.tzname()
'UTC+05:00'
Schedule
This is a 175-hour projects, so I keep it short in schedule (around 10 weeks). However, I’d like to go beyond after completing this project. I’m open to new ideas and would like to contribute to more implementations.
Pre-Community Bonding Period ( April ):
In this period, I will work on tickets to be more familiar with the code and workflow.
Community Bonding Period ( May ):
In this period, I will continue working on the pending PRs. I will also discuss with my mentors to finalize the UI and decide on a clear roadmap.
Week 1
- Design and add a user timezone table in the database.
- Design and implement the front-end UI for the setting page.
- Design and implement the API endpoint and db side operations.
Week 2,3
- Continue to implement the API endpoint.
- Test for the UI and API endpoint.
Week 4
- Add
listened_at_local
field to submit json. - Update the document for users by clarifying the accepted format of local timestamp.
- Write validation for the
listened_at_local
field.
Week5,6
- Modify the
listen
table by addinglistened_at_local
field. - Modify the functions of inserting and fetching listens regarding
listened_at
field
Week 7,8
- Write tests and debug for the modification.
Week 9
- Continue to debug and test if not finished.
- Write document for the work done.
Week 10
- Finish any left work.
- Submit code and document.
- prepare to go beyond with the community
About me
I am Youzhi Liang (feel free to call me yuzie, which is also my nickname in irc). I am a first year master student at Duke University. I majored in Electrical Engineering in my undergraduate study and am currently studying Computer science(minor in Economics). I have solid background in web development, iOS mobile app development and Natural Language Processing. I feel privileged to join this open-source community and I am really looking forward to making contributions to make our current product better.
I am new to open source, but I have been joining the discussions in the MetaBrainz IRC and community forum for some days. I find that I really love the way people discuss and help with each other in this community. This the first time I get in touch with a complex and influential projects, and I mastered lots of new skills during the process of getting familiar with the project. This is really a good start for me to become a professional software engineer. I really appreciate all the help from the community.
Other Information
Tell us about the computer(s) you have available for working on your SoC project!
- Mac mini M1
- MacBook pro Intel
When did you first start programming?
- Since my first undergraduate year, around 2016
What type of music do you listen to?
- Classic music and country music
What aspects of the project you’re applying for interest you the most?
- One aspect is that I like to do work which includes both front – end and back- end. Another is that when I look through the posts on the forum, I find some of people suggest the timezone feature would be useful, so I will be happy if my work can help improve the user experience.
Have you ever used MusicBrainz to tag your files?
- Yes, and still exploring features of Picard.
Have you contributed to other open source projects?
- I am new to open source, but I myself is benefitted a lot from the open source community while learning to develop software. So I hope to become an open source contributor so that I can serve for the open source community.
Recent project?
- Web application, iOS application and Natural Language Processing projects.
- See YouzhiL (Youzhi) · GitHub for detail
How much time do you have available, and how would you plan to use it?
- I plan to distribute 18 hour per week for this project from May and spend 10weeks to finish it.