Spent some time setting up my own Mastodon instance. Mostly just to try it out. I’m not sure if I’ll keep it going—managing a server I don’t really need sounds hard. It’s fun having @sam@warnick.me as my handle though.
I mostly followed two guides and setup my instance on a Linode with Docker:
I’m actually hosting the instance at https://social.warnick.me, but I wanted the handle to be @warnick.me. This wasn’t too difficult. Just needed to set LOCAL_DOMAIN and WEB_DOMAIN properly in .env.production, the update my nginx config to redirect the webfinger correctly. After those changes, it seems to be working?
I had a couple things stump me, but that was mostly me not being able to read. I missed that I needed to change my roots in the nginx config and a couple other things. But also, I ran the setup script, put in all the information, and it asked “Do you want me to save this to .env.production?” Yes please. And then it just didn’t. So I needed to add a few config options it was missing. And I put in the wrong values at a couple points so the web server couldn’t start up and I didn’t really know how to see the logs to debug because I’m a Docker n00b.
Then for funs, I made @blog@warnick.me and set up an IFTTT automation to post every time I post to the blog—followed this blog. Going to try that now…
I was having trouble with one of my algorithms. I would make changes to objects in an array, but those changes would not stick. It took me a long time to realize that it was because the objects were structs, which are passed by reference. So each time I was accessing, it was a different reference. Switched them to classes and now it works as expected. Still need to understand better when to use a struct vs a class.
Any, I got to the point that I can see cast a crew comparisons!
My second attempt at this screen
I’m still not sure how to best layout the information, especially on a phone. I think the center aligned text is a little difficult to scan. But, at least the data is there! I had to work with the data a bit because there are cases where the same person has multiple credits because they had multiple roles—writer, director, actor, etc. I need to dig into the data/my algorithm more, because I’m seeing some cases where I know someone is involved in both movies, but no results are showing up.
I’m also having issues with my debounce. Sometimes it will just not emit. So I might get rid of it. Do requests get cancelled if you make a bunch in quick succession? Need to look into that. Also sometimes not getting images loading in my search results.
Today I actually got to the UI. How exciting! I wanted to start with search, because I’ve never really done anything like that in SwiftUI before. I think it’s pretty straightforward.
Fairly happy with this so far
When the search sheet initially loads, I populate it with some current popular movies (according to TMDb.) Then, as the user searches, I hit search endpoint and display those results. I was pretty surprised that .searchable does not have a built in way to debounce or throttle the event. So I made my own workaround with Combine.
The first thing I tried was adding a debounce to the @State publisher for the query.
structSearch: View{
@Stateprivatevar query = ""var body: someView {
NavigationStack {
List(searchResults) { media in
...
}
.searchable(text: $query.value)
}
.onReceive(query.publisher.debounce(for: 0.3, scheduler: DispatchQueue.main)) { query in// Use the API to search and set results
}
}
}
This did not work for some reason. One day, I should understand why, but I don’t now. I thought you could subscribe to the state publisher?
The solution seemed to be to create an ObservableObject to hold the query.
structSearch: View{
privateclassQuery: ObservableObject{
@Publishedvar value = ""
}
@StateObjectprivatevar query = Query()
var body: someView {
NavigationStack {
List(searchResults) { media in
...
}
.searchable(text: $query.value)
}
.onReceive(query.$value.debounce(for: 0.3, scheduler: DispatchQueue.main)) { query in// Use the API to search and set results
}
}
}
A little overhead that seems unnecessary, but it works.
Was having a hard time with decoding some JSON. Was banging my head for like 30 mins. Turns out, I was simply trying to decode it as the wrong type—itself rather than a string 🤦🏻♂️.
I think I finally understand using an enum to decode values that could be multiple types. So in my case, results is an array that can hold Movie, TVShow, or Person. Can’t really throw in let results: [Movie | TVShow | Person] like you can in TypeScript. So, I made Media, which is an enum of movie, tvShow, and person. Helpfully, each type of media has the key media_type, so you know what you’re dealing with. When Media is being decoded, we look for media_type, and then based on that, create an enum with the correct associated type. Pretty cool. This is all pretty much stolen from an existing Swift TMDb library. Honestly, don’t know if I would’ve ever come up with this solution, and I doubt I explained it very clearly. But I like it, and I’m
not sure there are any other great solutions. When I get to the UI—which is taking me quite a while to get to…—I could use the enum to easily pick the correct View to use. Enums in Swift are powerful and I need to explore them more.
enumMedia: Decodable{
case movie(Movie)
case tvShow(TVShow)
case person(Person)
privateenumCodingKeys: String, CodingKey{
case mediaType
}
privateenumMediaType: String, Decodable, Equatable{
case movie
case tvShow = "tv"case person
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let mediaType = try container.decode(MediaType.self, forKey: .mediaType)
switch mediaType {
case .movie:
self = .movie(tryMovie(from: decoder))
case .tvShow:
self = .tvShow(tryTVShow(from: decoder))
case .person:
self = .person(tryPerson(from: decoder))
}
}
}
I’m already stretching the limits of my Swift knowledge. I’m looking at the multi search endpoint. It can return a Movie, TV Show, or Person, all together. I’m unsure how to handle that with Codable. It’s no problem in JS or even TS. I think I need to somehow create some sort of container to handle them all.
I found this lib. Taking a look at how they handle it, and they seem to use enums for it. An interesting solution that I don’t completely understand. Going to study it more.
Okay. I think I figured out what I’m going to work on. I’m going to make an app that will let me find common cast and crew between two movies or shows. More than once, I’ve been sitting on the couch and I’ll think something like “this movie feels kinda similar to this other show.” I’ll dig in on IMDB and turns out they have the same director of photography, or composer, or something like that. I’m sure this is something only I have run into or desired. I searched “movie compare” on the App Store and nothing came up, so obviously a huge untapped market.
I started in on it today and it’s exciting. So far, it seems to be small in scope, will have some fun design challenges, and will give me a change to use things I haven’t really done before.
I’m going to use The Movie Database’s API. Also looking into Boutique for storing data and whatnot. Nothing to show at the moment. Mostly spent the time getting things setup to use the API—mainly figuring out how to use URLSession and JSONDecoder with Codable, which I have used very little before. Excited to learn some new things!