Skip to content

Added MediaService functionality that allows users to control their media playing via Apple Music using the mpris packet types - #25

Open
Kanishk951 wants to merge 3 commits into
sannidhyaroy:nightlyfrom
Kanishk951:nightly
Open

Added MediaService functionality that allows users to control their media playing via Apple Music using the mpris packet types #25
Kanishk951 wants to merge 3 commits into
sannidhyaroy:nightlyfrom
Kanishk951:nightly

Conversation

@Kanishk951

Copy link
Copy Markdown

Currently only allows for one way (device to mac) control tho. Furthermore, it is only limited to Apple Music because for some stupid reason Apple doesn't have a universal media API, and what they do have is a hot mess that goes a tower up my smooth brain's mess-resolving capabilities. Anyway, please let me know if there's anything (which I'm pretty sure is) I can change to make it better and suit the overarching guidelines of the project. Additionally, please forgive me for, and lemme know of, any braindead piece of code that I might have written while undertaking this proj. (coffee at 2 am can only take you so far).

@Kanishk951

Copy link
Copy Markdown
Author

oh and i forgot to mention that i had to use apple script to get itunes/apple music to work with the proj. because for some another stupid reason apple doesn't have a swift (or even an objective-c) api for that.

@sannidhyaroy
sannidhyaroy self-requested a review November 3, 2023 08:07
@avichou

avichou commented Mar 30, 2024

Copy link
Copy Markdown

Currently only allows for one way (device to mac) control tho. Furthermore, it is only limited to Apple Music because for some stupid reason Apple doesn't have a universal media API, and what they do have is a hot mess that goes a tower up my smooth brain's mess-resolving capabilities. Anyway, please let me know if there's anything (which I'm pretty sure is) I can change to make it better and suit the overarching guidelines of the project. Additionally, please forgive me for, and lemme know of, any braindead piece of code that I might have written while undertaking this proj. (coffee at 2 am can only take you so far).

there gotta be a way to do with for youtube/youtube music within chrome. too bad i suck at programming , ill learn one day. but there must be a way to control chrome now playing with your android phone dont you think . anyway nice workflow man :)

@sannidhyaroy

sannidhyaroy commented Jan 29, 2026

Copy link
Copy Markdown
Owner

I have to look into this, because currently @sidevesh has an experimental mpris implementation. I haven't been able to get that to work, but as far as I understand, @sidevesh's implementation is for controlling media of remote from Soduto, while @Kanishk951's implementation is for controlling media (only Apple Music) of macOS from remote device, right?

Also, could you please clean up the commit messages so they describe what changed and why rather than subjective notes? Since, commit history is useful later for debugging, reviews, and understanding context, and these messages will end up in the permanent history, cleaning them up now would make that a lot easier. You may do an interactive git rebase, and reword those commit messages and force-push when rebasing is complete. Thanks for your help!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds MediaService functionality to enable remote control of Apple Music playback from connected devices using the KDE Connect mpris protocol. The implementation uses AppleScript bridge via AppleScriptObjC to communicate with Apple Music.

Changes:

  • Adds MediaService with support for play/pause, next/previous track, seek, volume control, and shuffle
  • Implements iTunesBridge using AppleScript for Apple Music integration
  • Adds required entitlements for Apple Music control and automation
  • Integrates SwiftyJSON dependency (though unused in final code)

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 28 comments.

Show a summary per file
File Description
Soduto/Services/MediaService/MediaService.swift Core service implementation with packet handling and media control logic
Soduto/Services/MediaService/iTunesBridge.swift Swift protocol/interface for AppleScript bridge
Soduto/Services/MediaService/iTunesBridge.applescript AppleScript implementation for Apple Music control
Soduto/Soduto.entitlements Adds Music control entitlements, removes addressbook entitlement
Soduto/Info.plist Adds NSAppleEventsUsageDescription for user permission
Soduto/AppDelegate.swift Registers MediaService with service manager
Soduto.xcodeproj/project.pbxproj Adds new files, SwiftyJSON dependency, changes team IDs and security settings
SharedUserDefaults.swift Changes suite name to different team ID
README Adds unrelated SwiftAutomation documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

set (newPos) {
if let iTunesBridge = iTunesBridge {

print("seeking to \(newPos)")

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug print statements should be removed or replaced with proper logging using the Log framework that's used elsewhere in the codebase (e.g., Log.debug?.message()).

Suggested change
print("seeking to \(newPos)")
Log.debug?.message("Seeking to \(newPos)")

Copilot uses AI. Check for mistakes.
Comment on lines +264 to +278
print("track duration is \(totalTime)")
var isPlaying: Bool = true

playerState = iTunesBridge?.playerState as? PlayerState ?? .stopped

switch playerState {
case .paused: isPlaying = false
case .stopped: isPlaying = false
default: break
// since now playing is already true we dont need to change a thing
}

print(info as Any)

print("pos is \(pos)")

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug print statements should be removed or replaced with proper logging using the Log framework that's used elsewhere in the codebase (e.g., Log.debug?.message()).

Copilot uses AI. Check for mistakes.
artist = info["trackArtist"] as? String ?? ""


let totalTime: Double = ((iTunesBridge?.trackDuration as! Double)) * 1000

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This force unwrap with force cast could crash if iTunesBridge.trackDuration is nil or not a Double. Consider using safer unwrapping with proper error handling.

Suggested change
let totalTime: Double = ((iTunesBridge?.trackDuration as! Double)) * 1000
var totalTime: Double = 0
if let duration = iTunesBridge?.trackDuration as? Double {
totalTime = duration * 1000
}

Copilot uses AI. Check for mistakes.
Comment thread Soduto/AppDelegate.swift
static let logLevelConfigurationKey = "com.soduto.logLevel"

override init() {

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an unnecessary empty line between the opening brace and the code. This should be removed for consistency with the rest of the codebase.

Suggested change

Copilot uses AI. Check for mistakes.
return 0
}
set (newVol) {
if let iTunesBridge = iTunesBridge { iTunesBridge.soundVolume = newVol as NSNumber

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The line is missing formatting with proper spacing before iTunesBridge.soundVolume. The line appears broken and should have proper indentation.

Suggested change
if let iTunesBridge = iTunesBridge { iTunesBridge.soundVolume = newVol as NSNumber
if let iTunesBridge = iTunesBridge {
iTunesBridge.soundVolume = newVol as NSNumber

Copilot uses AI. Check for mistakes.
843E178A1E26B613001D0444 /* Embed Login Items */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
buildActionMask = 12;

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The buildActionMask has been changed from 2147483647 to 12. This value typically should be 2147483647 (which equals 2^31 - 1) to indicate "all actions". Changing it to 12 may prevent certain build phases from running. This change should be reverted unless there's a specific reason for it.

Suggested change
buildActionMask = 12;
buildActionMask = 2147483647;

Copilot uses AI. Check for mistakes.
Comment on lines +23 to 24
<key>com.apple.security.automation.apple-events</key>
<true/>

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entitlement key 'com.apple.security.personal-information.addressbook' has been removed from the entitlements file. However, the codebase has existing functionality that accesses contacts (e.g., SendMessageWindowController.swift uses CNContactStore). Removing this entitlement will break that existing functionality. This entitlement should be retained.

Copilot uses AI. Check for mistakes.
// basically the player actually playing the audio.
}

// MARK: Struct Decleration

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spelling "Decleration" is incorrect. It should be "Declaration".

Suggested change
// MARK: Struct Decleration
// MARK: Struct Declaration

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +14
import MediaPlayer
import SwiftyJSON

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MediaPlayer import is unused and should be removed. The code doesn't use any MediaPlayer framework functionality.

Suggested change
import MediaPlayer
import SwiftyJSON
import SwiftyJSON

Copilot uses AI. Check for mistakes.
CURRENT_PROJECT_VERSION = 18;
DEVELOPMENT_TEAM = P8CGT2P7HB;
DEVELOPMENT_TEAM = 73583QR2DF;
ENABLE_HARDENED_RUNTIME = NO;

Copilot AI Jan 29, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Soduto target has ENABLE_HARDENED_RUNTIME explicitly disabled for both Debug and Release, which removes macOS hardened runtime protections (e.g., library validation and certain code injection mitigations) from the main app. An attacker who can influence the local environment (e.g., via malicious injected libraries or tooling) will have a much easier time modifying the running process or abusing its entitlements when hardened runtime is off. Consider re-enabling hardened runtime for the main app (especially for Release builds) and only relaxing it in narrowly scoped debug or helper targets if absolutely required.

Suggested change
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_HARDENED_RUNTIME = YES;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants