diff --git a/locales/en-US.json b/locales/en-US.json index 8da3ccda7..2d2217917 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -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", diff --git a/src/invidious/routes/subscriptions.cr b/src/invidious/routes/subscriptions.cr index 6c7422116..e07b62c91 100644 --- a/src/invidious/routes/subscriptions.cr +++ b/src/invidious/routes/subscriptions.cr @@ -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) diff --git a/src/invidious/user/exports.cr b/src/invidious/user/exports.cr index 9ce823ae9..adc604825 100644 --- a/src/invidious/user/exports.cr +++ b/src/invidious/user/exports.cr @@ -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) diff --git a/src/invidious/views/user/data_control.ecr b/src/invidious/views/user/data_control.ecr index 1ada97122..a7271703f 100644 --- a/src/invidious/views/user/data_control.ecr +++ b/src/invidious/views/user/data_control.ecr @@ -53,11 +53,11 @@ <%= I18n.translate(locale, "Export") %>
- <%= I18n.translate(locale, "Export subscriptions as OPML") %> + <%= I18n.translate(locale, "Export subscriptions as OPML (for FreeTube)") %>
- <%= I18n.translate(locale, "Export subscriptions as OPML (for NewPipe & FreeTube)") %> + <%= I18n.translate(locale, "Export subscriptions as JSON (for NewPipe)") %>