Skip to content
This repository has been archived by the owner on Mar 22, 2023. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jan4843 committed Jul 3, 2022
0 parents commit 7f8969b
Show file tree
Hide file tree
Showing 62 changed files with 3,169 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# CocoaPods
Pods/

# Xcode
xcuserdata/
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ruby-2.7.6
19 changes: 19 additions & 0 deletions Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
platform :ios, '15.4'

target 'Tivu' do
use_frameworks!

pod 'MobileVLCKit', '~> 3.4.0'

target 'TivuTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end
end
16 changes: 16 additions & 0 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
PODS:
- MobileVLCKit (3.4.0)

DEPENDENCIES:
- MobileVLCKit (~> 3.4.0)

SPEC REPOS:
trunk:
- MobileVLCKit

SPEC CHECKSUMS:
MobileVLCKit: 20ccee43f7788a94ea1f67179e33d9600779dfd9

PODFILE CHECKSUM: 7c3c29c7ec55e661d01e80dce27e330daf4baaa0

COCOAPODS: 1.11.3
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Tivu

<table>
<tr>
<td>
<img src="Screenshots/channels.png"/>
</td>
<td>
<img src="Screenshots/settings.png"/>
</td>
</tr>
<tr>
<td colspan=2>
<img src="Screenshots/player.png"/>
</td>
</tr>
</table>

## Build

1. Ensure that the CocoaPods gem installed, preferably using a Ruby version manager (rbenv, rvm, asdf-ruby):

```console
$ gem install cocoapods
```

2. Download the dependencies required by the project:

```console
$ pod install
```

3. Open the project workspace with Xcode:

```console
$ open -a Xcode Tivu.xcworkspace
```

## Clarifications

The reason for manually dealing with `NSBatchUpdateRequest`, `NSBatchDeleteRequest`, `mergeChanges(fromRemoteContextSave:into:)` is the following: deleting all entities from a Core Data persistence store would require the use of `NSBatchDeleteRequest`. Such operations don't trigger any Core Data save notifications since they operate at the persistence store level and not within a `NSManagedObjectContext`. When inserting new data, the view context would have duplicate data. A solution to that would be manually triggering a save notification for *all* deleted object IDs which could be quite expensive.
Instead, the used approach, inserts new entities ensuring that they replace the existing ones (if already there), maintaining the original object ID thanks to Core Data constraints and `NSMergePolicy.mergeByPropertyObjectTrump`. This allows to manually trigger a much smaller save notification for only the delta of actually deleted objects. (All inserted objects do generate the same size of save notifications, but this is handled by Core Data and could potentially be batched.)

## Known Issues

- Rotating the device during playback may occasionally dismiss the video player. This appears to be an unwanted behavior of SwiftUI `fullScreenCover(isPresented:onDismiss:content:)`.

To also consider during development:

- Device rotation may not work when the app is started from Xcode. Restarting the app from the device fixes this.
- The video player is not optimized for Simulator and playback is therefore choppy and may occasionally crash. Using the app on an actual device doesn't result in these issue.
Binary file added Screenshots/channels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/player.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Screenshots/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
953 changes: 953 additions & 0 deletions Tivu.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions Tivu.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Tivu.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
11 changes: 11 additions & 0 deletions Tivu/Assets.xcassets/AccentColor.colorset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
56 changes: 56 additions & 0 deletions Tivu/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "Frame 1-2.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "Frame 1-1.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "Frame 1.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Tivu/Assets.xcassets/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
1 change: 1 addition & 0 deletions Tivu/Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#import "MobileVLCKit/MobileVLCKit.h"
15 changes: 15 additions & 0 deletions Tivu/Domains/TVHeadend/TVHeadendServer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
struct TVHeadendServer: Equatable {
let url: URL

var xmltvURL: URL {
let url = url.appendingPathComponents(["xmltv", "channels"])
var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true)!
urlComponents.queryItems = urlComponents.queryItems ?? []
urlComponents.queryItems?.append(URLQueryItem(name: "lcn", value: "1"))
return urlComponents.url!
}

func streamURL(for channel: Channel) -> URL {
url.appendingPathComponents(["stream", "channel", channel.id])
}
}
23 changes: 23 additions & 0 deletions Tivu/Domains/XMLTV/Program+XMLTV.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation

extension Program.Number {
internal init?(xmltvString: String) {
let components = xmltvString
.replacingOccurrences(of: " ", with: "")
.components(separatedBy: ".")
guard components.count > 1 else { return nil }

self.init(
season: Self.parseComponent(components[0]),
episode: Self.parseComponent(components[1])
)
}

fileprivate static func parseComponent(_ xmltvComponent: String) -> Int? {
let value = xmltvComponent
.components(separatedBy: "/")
.first ?? ""
guard let value = Int(value) else { return nil }
return value + 1
}
}
Loading

0 comments on commit 7f8969b

Please sign in to comment.