mirror of
https://github.com/iv-org/invidious.git
synced 2026-11-01 17:37:15 +00:00
Add subscription JSON export for NewPipe (#5826)
The current option to export subscriptions for NewPipe (`Export subscriptions as OPML (for NewPipe & FreeTube)`) isn't accepted by NewPipe anymore. As far as I can tell, NewPipe only accepts importing from its own SQLite database, from Google Account CSV export and from its own JSON export format. This is mentioned in https://github.com/iv-org/invidious/issues/5438. This PR adds support to export subscriptions in the NewPipe compatible format. I'm looking for input on a few points: - I'm not a huge fan of hardcoding the NewPipe version in the export, but it is required by NewPipe to recognize it as a valid file. If someone has a better idea I'm all ears but I think it's the only way. In any case, NewPipe can import formats in a backwards compatible way in the future so it shouldn't be a huge deal. - I haven't checked if the OPML export option actually works for FreeTube. If it doesn't, it should probably be removed altogether, for now I just removed the `(for NewPipe)` part. - The translations would need to be updated, but I don't know how that is handled in this project so I need some help there. The new format looks like this: ``` { "subscriptions": [ { "service_id": 0, "url": "https://www.youtube.com/channel/UCHnyfMqiRRG1u-2MsSQLbXA", "name": "Veritasium" }, { "service_id": 0, "url": "https://www.youtube.com/channel/UC6nSFpj9HTCZ5t-N3Rm3-HA", "name": "Vsauce" } ], "app_version": "0.29.0", "app_version_int": 1014 } ``` * add subscription json export for NewPipe * remove old newpipe export format * make newpipe export values constant * remove duplicate export option, add i18n keys * Convert to_newpipe to a serializable struct * Use same naming format as NewPipe for the exported subscriptions --------- Co-authored-by: Fijxu <fijxu@nadeko.net>
This commit is contained in:
@@ -51,8 +51,8 @@
|
||||
"Import NewPipe subscriptions (.json)": "Import NewPipe subscriptions (.json)",
|
||||
"Import NewPipe data (.zip)": "Import NewPipe data (.zip)",
|
||||
"Export": "Export",
|
||||
"Export subscriptions as OPML": "Export subscriptions as OPML",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Export subscriptions as OPML (for NewPipe & FreeTube)",
|
||||
"Export subscriptions as OPML (for FreeTube)": "Export subscriptions as OPML (for FreeTube)",
|
||||
"Export subscriptions as JSON (for NewPipe)": "Export subscriptions as JSON (for NewPipe)",
|
||||
"Export data as JSON": "Export Invidious data as JSON",
|
||||
"Delete account?": "Delete account?",
|
||||
"History": "History",
|
||||
|
||||
@@ -80,30 +80,28 @@ module Invidious::Routes::Subscriptions
|
||||
subscriptions.sort_by!(&.author.downcase)
|
||||
|
||||
if action_takeout
|
||||
if format == "json"
|
||||
env.response.content_type = "application/json"
|
||||
env.response.headers["content-disposition"] = "attachment"
|
||||
env.response.content_type = "application/json"
|
||||
|
||||
# Exports the NewPipe with the same naming format NewPipe
|
||||
# uses for their exports
|
||||
# Exmaple: `newpipe_subscriptions_202610312013`
|
||||
export_time = Time.local.to_s("%Y%m%d%H%M")
|
||||
env.response.headers["Content-Disposition"] = "attachment; filename=\"newpipe_subscriptions_#{export_time}\""
|
||||
|
||||
if format == "json"
|
||||
return Invidious::User::Export.to_invidious(user)
|
||||
elsif format == "newpipe_json"
|
||||
return Invidious::User::Export.to_newpipe(subscriptions)
|
||||
else
|
||||
env.response.content_type = "application/xml"
|
||||
env.response.headers["content-disposition"] = "attachment"
|
||||
export = XML.build do |xml|
|
||||
xml.element("opml", version: "1.1") do
|
||||
xml.element("body") do
|
||||
if format == "newpipe"
|
||||
title = "YouTube Subscriptions"
|
||||
else
|
||||
title = "Invidious Subscriptions"
|
||||
end
|
||||
title = "Invidious Subscriptions"
|
||||
|
||||
xml.element("outline", text: title, title: title) do
|
||||
subscriptions.each do |channel|
|
||||
if format == "newpipe"
|
||||
xml_url = "https://www.youtube.com/feeds/videos.xml?channel_id=#{channel.id}"
|
||||
else
|
||||
xml_url = "#{HOST_URL}/feed/channel/#{channel.id}"
|
||||
end
|
||||
xml_url = "#{HOST_URL}/feed/channel/#{channel.id}"
|
||||
|
||||
xml.element("outline", text: channel.author, title: channel.author,
|
||||
"type": "rss", xmlUrl: xml_url)
|
||||
|
||||
@@ -2,6 +2,42 @@ struct Invidious::User
|
||||
module Export
|
||||
extend self
|
||||
|
||||
struct NewPipe
|
||||
include JSON::Serializable
|
||||
|
||||
# Hardcoded NewPipe values that are needed
|
||||
# so NewPipe can import the JSON.
|
||||
private APP_VERSION = "0.29.0"
|
||||
private APP_VERSION_INT = 1014
|
||||
private YT_SERVICE_ID = 0
|
||||
|
||||
getter subscriptions : Array(Subscription)
|
||||
|
||||
struct Subscription
|
||||
include JSON::Serializable
|
||||
|
||||
getter service_id : Int32 = YT_SERVICE_ID
|
||||
getter url : String
|
||||
getter name : String
|
||||
|
||||
def initialize(channel : InvidiousChannel)
|
||||
@url = "https://www.youtube.com/channel/" + channel.id
|
||||
@name = channel.author
|
||||
end
|
||||
end
|
||||
|
||||
getter app_version : String = APP_VERSION
|
||||
getter app_version_int : Int32 = APP_VERSION_INT
|
||||
|
||||
def initialize(channels : Array(InvidiousChannel))
|
||||
@subscriptions = channels.map { |channel| Subscription.new(channel) }
|
||||
end
|
||||
end
|
||||
|
||||
def to_newpipe(subscriptions : Array(InvidiousChannel))
|
||||
NewPipe.new(subscriptions).to_json
|
||||
end
|
||||
|
||||
def to_invidious(user : User)
|
||||
playlists = Invidious::Database::Playlists.select_like_iv(user.email)
|
||||
|
||||
|
||||
@@ -53,11 +53,11 @@
|
||||
<legend><%= I18n.translate(locale, "Export") %></legend>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<a href="/subscription_manager?action_takeout=1"><%= I18n.translate(locale, "Export subscriptions as OPML") %></a>
|
||||
<a href="/subscription_manager?action_takeout=1&format=opml"><%= I18n.translate(locale, "Export subscriptions as OPML (for FreeTube)") %></a>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<a href="/subscription_manager?action_takeout=1&format=newpipe"><%= I18n.translate(locale, "Export subscriptions as OPML (for NewPipe & FreeTube)") %></a>
|
||||
<a href="/subscription_manager?action_takeout=1&format=newpipe_json"><%= I18n.translate(locale, "Export subscriptions as JSON (for NewPipe)") %></a>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
|
||||
Reference in New Issue
Block a user