Skip to content

Commit

Permalink
Merge branch 'develop' into close-4383
Browse files Browse the repository at this point in the history
  • Loading branch information
uiryuu committed May 9, 2023
2 parents c03a880 + 4922821 commit 800e5f1
Show file tree
Hide file tree
Showing 21 changed files with 283 additions and 720 deletions.
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
github: [iina]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
ko_fi: iina_app
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: iina_app
Expand Down
51 changes: 42 additions & 9 deletions browser/Chrome_Open_In_IINA/background.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
import { updateBrowserAction, openInIINA } from "./common.js";
import { updateBrowserAction, openInIINA, getOptions } from "./common.js";

updateBrowserAction();

[["page", "url"], ["link", "linkUrl"], ["video", "srcUrl"], ["audio", "srcUrl"]].forEach(([item, linkType]) => {
chrome.contextMenus.create({
title: `Open this ${item} in IINA`,
id: `open${item}iniina`,
contexts: [item],
onclick: (info, tab) => {
openInIINA(tab.id, info[linkType]);
},
const dict = {
page: "pageUrl",
link: "linkUrl",
video: "srcUrl",
audio: "srcUrl",
};

Object.keys(dict).forEach((item) => {
chrome.contextMenus.create({
title: `Open this ${item} in IINA`,
id: `openiniina_${item}`,
contexts: [item],
});
});

chrome.contextMenus.onClicked.addListener(function (info, tab) {
if (info.menuItemId.startsWith("openiniina")) {
const key = info.menuItemId.split("_")[1];
const url = info[dict[key]];
if (url) {
openInIINA(tab.id, url);
}
}
});

chrome.action.onClicked.addListener(() => {
// get active window
chrome.tabs.query({ currentWindow: true, active: true }, (tabs) => {
if (tabs.length === 0) {
return;
}
// TODO: filter url
const tab = tabs[0];
if (tab.id === chrome.tabs.TAB_ID_NONE) {
return;
}
getOptions((options) => {
openInIINA(tab.id, tab.url, {
mode: options.iconActionOption,
});
});
});
});
49 changes: 21 additions & 28 deletions browser/Chrome_Open_In_IINA/common.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

class Option {
constructor(name, type, defaultValue) {
this.name = name;
Expand Down Expand Up @@ -59,7 +58,7 @@ export function restoreOptions() {

export function openInIINA(tabId, url, options = {}) {
const baseURL = `iina://open?`;
const params = [`url=${encodeURIComponent(url)}`];
const params = [`url=${encodeURIComponent(url).replace(/'/g, '%27')}`];
switch (options.mode) {
case "fullScreen":
params.push("full_screen=1"); break;
Expand All @@ -71,33 +70,27 @@ export function openInIINA(tabId, url, options = {}) {
if (options.newWindow) {
params.push("new_window=1");
}
const code = `
var link = document.createElement('a');
link.href='${baseURL}${params.join("&")}';
document.body.appendChild(link);
link.click();
`;
chrome.tabs.executeScript(tabId, { code });

chrome.scripting.executeScript({
args: [baseURL, params],
target: { tabId: tabId },
func: openIINA,
});
}

const openIINA = (baseURL, params) => {
var link = document.createElement("a");
link.href = `${baseURL}${params.join("&")}`;
document.body.appendChild(link);
link.click();
};

export function updateBrowserAction() {
getOptions((options) => {
if (options.iconAction === "clickOnly") {
chrome.browserAction.setPopup({ popup: "" });
chrome.browserAction.onClicked.addListener(() => {
// get active window
chrome.tabs.query({ currentWindow: true, active: true }, (tabs) => {
if (tabs.length === 0) { return; }
// TODO: filter url
const tab = tabs[0];
if (tab.id === chrome.tabs.TAB_ID_NONE) { return; }
openInIINA(tab.id, tab.url, {
mode: options.iconActionOption,
});
});
});
} else {
chrome.browserAction.setPopup({ popup: "popup.html" });
}
});
getOptions((options) => {
if (options.iconAction === "clickOnly") {
chrome.action.setPopup({ popup: "" });
} else {
chrome.action.setPopup({ popup: "popup.html" });
}
});
}
12 changes: 7 additions & 5 deletions browser/Chrome_Open_In_IINA/manifest.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
{
"manifest_version": 2,
"manifest_version": 3,

"name": "Open In IINA",
"description": "Open videos and audios in IINA.",
"version": "2.0.0",
"version": "2.0.2",
"options_page": "options.html",
"background": {
"page": "background.html"
"service_worker": "background.js",
"type": "module"
},
"browser_action": {
"action": {
"default_icon": "icon.png",
"default_title": "Open In IINA"
},
"permissions": [
"tabs",
"activeTab",
"contextMenus",
"storage"
"storage",
"scripting"
],
"icons": {
"16": "icon16.png",
Expand Down
12 changes: 11 additions & 1 deletion iina-cli/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ if userArgs.contains(where: { $0 == "--help" || $0 == "-h" }) {
--keep-running:
Normally iina-cli launches IINA and quits immediately. Supply this option
if you would like to keep it running until the main application exits.
--music-mode:
Enter music mode after opening the media.
--pip:
Enter Picture-in-Picture after opening the media.
Enter Picture-in-Picture after opening the media. Music mode does not
support Picture-in-Picture.
--help | -h:
Print this message.
Expand All @@ -66,6 +69,13 @@ if userArgs.contains(where: { $0 == "--help" || $0 == "-h" }) {
exit(0)
}

if userArgs.contains("--music-mode"), userArgs.contains("--pip") {
// Music mode does not support Picture-in-Picture. Combining these options is not permitted.
print("Cannot specify both --music-mode and --pip")
// Command line usage error.
exit(EX_USAGE)
}

var isStdin = false
var userSpecifiedStdin = false

Expand Down
8 changes: 0 additions & 8 deletions iina.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,6 @@
E3CB258F222799B800A62C47 /* MPVHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3CB258E222799B800A62C47 /* MPVHook.swift */; };
E3CB75BB1FD998F5004DB10A /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A886F21E26CA24008755BB /* Regex.swift */; };
E3CB75BD1FDACB82004DB10A /* SavedFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3CB75BC1FDACB82004DB10A /* SavedFilter.swift */; };
E3DBD239218B057A00B3AFBF /* Translators.json in Resources */ = {isa = PBXBuildFile; fileRef = E3DBD238218B057A00B3AFBF /* Translators.json */; };
E3DBD23B218B199700B3AFBF /* Translators.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3DBD23A218B199700B3AFBF /* Translators.swift */; };
E3DBD23E218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3DBD23C218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.swift */; };
E3DBD23F218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E3DBD23D218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.xib */; };
E3DE8DCD1FD8166A0021921C /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3DE8DCC1FD8166A0021921C /* main.swift */; };
Expand Down Expand Up @@ -1664,8 +1662,6 @@
E3CB258A2222885E00A62C47 /* JavascriptAPIOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavascriptAPIOverlay.swift; sourceTree = "<group>"; };
E3CB258E222799B800A62C47 /* MPVHook.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MPVHook.swift; sourceTree = "<group>"; };
E3CB75BC1FDACB82004DB10A /* SavedFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedFilter.swift; sourceTree = "<group>"; };
E3DBD238218B057A00B3AFBF /* Translators.json */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.json; path = Translators.json; sourceTree = "<group>"; tabWidth = 4; };
E3DBD23A218B199700B3AFBF /* Translators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Translators.swift; sourceTree = "<group>"; };
E3DBD23C218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowContributorAvatarItem.swift; sourceTree = "<group>"; };
E3DBD23D218EF4F100B3AFBF /* AboutWindowContributorAvatarItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutWindowContributorAvatarItem.xib; sourceTree = "<group>"; };
E3DE8DCA1FD8166A0021921C /* iina-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "iina-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -2014,8 +2010,6 @@
845AC09E1E1AE6C10080B614 /* Localizable.strings */,
84AF03D41E67492C003E3753 /* Contribution.rtf */,
8483FAFF1EDFF325000F55D6 /* Credits.rtf */,
E3DBD238218B057A00B3AFBF /* Translators.json */,
E3DBD23A218B199700B3AFBF /* Translators.swift */,
);
name = Assets;
sourceTree = "<group>";
Expand Down Expand Up @@ -2593,7 +2587,6 @@
84A0BA951D2F9E9600BC8DA1 /* MainMenu.xib in Resources */,
8400D5D81E1AB31B006785F5 /* AboutWindowController.xib in Resources */,
8400D5F31E1AB348006785F5 /* PrefSubViewController.xib in Resources */,
E3DBD239218B057A00B3AFBF /* Translators.json in Resources */,
84D0FB821F5E6A3800C6A6A7 /* FreeSelectingViewController.xib in Resources */,
8400D5E11E1AB32F006785F5 /* PrefUIViewController.xib in Resources */,
E338368A202651CF00ABC812 /* PrefOSCToolbarDraggingItemViewController.xib in Resources */,
Expand Down Expand Up @@ -2741,7 +2734,6 @@
E3CB75BD1FDACB82004DB10A /* SavedFilter.swift in Sources */,
E337D5E4241C12BE00B5729A /* PrefPluginPermissionListView.swift in Sources */,
E342832F20B7149800139865 /* Logger.swift in Sources */,
E3DBD23B218B199700B3AFBF /* Translators.swift in Sources */,
84F725561D4783EE000DEF1B /* VolumeSliderCell.swift in Sources */,
845040401E0ACADD0079C194 /* MPVNode.swift in Sources */,
84795C3A1E083EE30059A648 /* PrefControlViewController.swift in Sources */,
Expand Down
68 changes: 4 additions & 64 deletions iina/AboutWindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,10 @@ class AboutWindowController: NSWindowController {
@IBOutlet weak var creditsButton: AboutWindowButton!
@IBOutlet weak var tabView: NSTabView!
@IBOutlet weak var contributorsCollectionView: NSCollectionView!
@IBOutlet weak var contributorsCollectionViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var contributorsFooterView: NSVisualEffectView!
@IBOutlet weak var contributorsFooterImage: NSImageView!
@IBOutlet weak var translatorsTableView: NSTableView!

private lazy var contributors = getContributors()
private lazy var translators = loadTraslators()

override func windowDidLoad() {
super.windowDidLoad()
Expand Down Expand Up @@ -130,9 +127,6 @@ class AboutWindowController: NSWindowController {
}

contributorsCollectionView.enclosingScrollView?.contentInsets.bottom = contributorsFooterView.frame.height * loc[colors.firstIndex(of: 0)! - 1]

translatorsTableView.dataSource = self
translatorsTableView.delegate = self
}

@objc func openCommitLink() {
Expand All @@ -151,6 +145,10 @@ class AboutWindowController: NSWindowController {
@IBAction func contributorsBtnAction(_ sender: Any) {
NSWorkspace.shared.open(URL(string: AppData.contributorsLink)!)
}

@IBAction func translatorsBtnAction(_ sender: Any) {
NSWorkspace.shared.open(URL(string: AppData.crowdinMembersLink)!)
}
}

extension AboutWindowController: NSCollectionViewDataSource {
Expand Down Expand Up @@ -178,9 +176,6 @@ extension AboutWindowController: NSCollectionViewDataSource {
let prevCount = self.contributors.count
guard let data = response.content,
let contributors = try? JSONDecoder().decode([Contributor].self, from: data) else {
DispatchQueue.main.async {
self.contributorsCollectionViewHeightConstraint.constant = 24
}
return
}
self.contributors.append(contentsOf: contributors)
Expand Down Expand Up @@ -211,61 +206,6 @@ fileprivate let identifierMap: [NSUserInterfaceItemIdentifier: NSUserInterfaceIt
.translatorColumn: .translatorCell
]

extension AboutWindowController: NSTableViewDataSource, NSTableViewDelegate {
func numberOfRows(in tableView: NSTableView) -> Int {
return translators.count
}

func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return translators[at: row]
}

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard
let translatorInfo = translators[at: row],
let tableColumn = tableColumn,
let identifier = identifierMap[tableColumn.identifier],
let view = tableView.makeView(withIdentifier: identifier, owner: self) as? NSTableCellView
else { return nil }
if identifier == .langCell {
view.textField!.stringValue = translatorInfo["lang"]!
} else {
view.textField!.setHTMLValue(translatorInfo["translator"]!)
}
return view
}

private func loadTraslators() -> [[String: String]] {
let locale = NSLocale.current
var result: [[String: String]] = []

let languages = Translator.all.keys.sorted()

for langCode in languages {
let translators = Translator.all[langCode]!
let splitted = langCode.split(separator: "-").map(String.init)
let baseLangCode = locale.localizedString(forLanguageCode: splitted[0]) ?? ""
let language: String
if splitted.count == 1 {
language = baseLangCode
} else {
let desc = locale.localizedString(forScriptCode: splitted[1]) ??
locale.localizedString(forRegionCode: splitted[1]) ?? ""
language = "\(baseLangCode) (\(desc))"
}
for (index, translator) in translators.enumerated() {
let urlString = translator.url == nil ? nil : "(<a href=\"\(translator.url!)\">\(translator.title!)</a>)"
let emailString = translator.email == nil ? nil : "<a href=\"mailto:\(translator.email!)\">\(translator.email!)</a>"
result.append([
"lang": index == 0 ? language : "",
"translator": ["\(translator.name)", urlString, emailString].compactMap { $0 }.joined(separator: " ")
])
}
}
return result
}
}

class AboutWindowButton: NSButton {

override func awakeFromNib() {
Expand Down
1 change: 1 addition & 0 deletions iina/AppData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct AppData {

static let githubLink = "https://github.com/iina/iina"
static let contributorsLink = "https://github.com/iina/iina/graphs/contributors"
static let crowdinMembersLink = "https://crowdin.com/project/iina/members"
static let wikiLink = "https://github.com/iina/iina/wiki"
static let websiteLink = "https://iina.io"
static let emailLink = "developers@iina.io"
Expand Down
21 changes: 18 additions & 3 deletions iina/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,20 @@ class AppDelegate: NSObject, NSApplicationDelegate, SPUUpdaterDelegate {
}
}

// enter PIP
if #available(macOS 10.12, *), let pc = lastPlayerCore, commandLineStatus.enterPIP {
pc.mainWindow.enterPIP()
if let pc = lastPlayerCore {
if commandLineStatus.enterMusicMode {
if commandLineStatus.enterPIP {
// PiP is not supported in music mode. Combining these options is not permitted and is
// rejected by iina-cli. The IINA executable must have been invoked directly with
// arguments.
Logger.log("Cannot specify both --music-mode and --pip", level: .error)
// Command line usage error.
exit(EX_USAGE)
}
pc.switchToMiniPlayer()
} else if #available(macOS 10.12, *), commandLineStatus.enterPIP {
pc.mainWindow.enterPIP()
}
}
}

Expand Down Expand Up @@ -847,6 +858,7 @@ struct CommandLineStatus {
var isCommandLine = false
var isStdin = false
var openSeparateWindows = false
var enterMusicMode = false
var enterPIP = false
var mpvArguments: [(String, String)] = []
var iinaArguments: [(String, String)] = []
Expand Down Expand Up @@ -881,6 +893,9 @@ struct CommandLineStatus {
if name == "separate-windows" {
openSeparateWindows = true
}
if name == "music-mode" {
enterMusicMode = true
}
if name == "pip" {
enterPIP = true
}
Expand Down
Loading

0 comments on commit 800e5f1

Please sign in to comment.