diff options
| author | Omar Roth <omarroth@hotmail.com> | 2019-02-16 09:57:09 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-16 09:57:09 -0600 |
| commit | 6a8a49d8efec065d7d2745d6bc66a4319546798e (patch) | |
| tree | bcc1806159e28ba6d7ddd8fdd8ecf492a39d11e4 /src | |
| parent | 7e2954c325d7ee0303de3197cdfebd616bf0a9d5 (diff) | |
| parent | 27663b10a256cd3ddb31b3b5e013daeaf577155f (diff) | |
| download | invidious-6a8a49d8efec065d7d2745d6bc66a4319546798e.tar.gz invidious-6a8a49d8efec065d7d2745d6bc66a4319546798e.tar.bz2 invidious-6a8a49d8efec065d7d2745d6bc66a4319546798e.zip | |
Merge branch 'master' into 347-screenshots
Diffstat (limited to 'src')
| -rw-r--r-- | src/invidious.cr | 58 | ||||
| -rw-r--r-- | src/invidious/channels.cr | 128 | ||||
| -rw-r--r-- | src/invidious/helpers/helpers.cr | 113 | ||||
| -rw-r--r-- | src/invidious/mixes.cr | 5 | ||||
| -rw-r--r-- | src/invidious/playlists.cr | 111 | ||||
| -rw-r--r-- | src/invidious/users.cr | 33 | ||||
| -rw-r--r-- | src/invidious/views/components/subscribe_widget_script.ecr | 4 |
7 files changed, 282 insertions, 170 deletions
diff --git a/src/invidious.cr b/src/invidious.cr index 72ac8caf..222b82ae 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -163,9 +163,10 @@ before_all do |env| # Invidious users only have SID if !env.request.cookies.has_key? "SSID" - user = PG_DB.query_one?("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User) + email = PG_DB.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String) - if user + if email + user = PG_DB.query_one("SELECT * FROM users WHERE email = $1", email, as: User) challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week) env.set "challenge", challenge @@ -177,7 +178,7 @@ before_all do |env| end else begin - user = get_user(sid, headers, PG_DB, false) + user, sid = get_user(sid, headers, PG_DB, false) challenge, token = create_response(user.email, "sign_out", HMAC_KEY, PG_DB, 1.week) env.set "challenge", challenge @@ -312,7 +313,7 @@ get "/watch" do |env| end if watched && !watched.includes? id - PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE $2 = id", [id], user.as(User).id) + PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE email = $2", [id], user.as(User).email) end if nojs @@ -818,7 +819,7 @@ post "/login" do |env| # Prefer Authenticator app and SMS over unsupported protocols if challenge_results[0][-1][0][0][8] != 6 && challenge_results[0][-1][0][0][8] != 9 tfa = challenge_results[0][-1][0].as_a.select { |auth_type| auth_type[8] == 6 || auth_type[8] == 9 }[0] - select_challenge = "[#{challenge_results[0][-1][0].as_a.index(tfa).not_nil!}]" + select_challenge = "[2,null,null,null,[#{tfa[8]}]]" tl = challenge_results[1][2] @@ -880,7 +881,7 @@ post "/login" do |env| sid = login.cookies["SID"].value - user = get_user(sid, headers, PG_DB) + user, sid = get_user(sid, headers, PG_DB) # We are now logged in @@ -986,7 +987,7 @@ post "/login" do |env| if Crypto::Bcrypt::Password.new(user.password.not_nil!) == password sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - PG_DB.exec("UPDATE users SET id = id || $1 WHERE LOWER(email) = LOWER($2)", [sid], email) + PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.now) if Kemal.config.ssl || CONFIG.https_only secure = true @@ -1024,13 +1025,14 @@ post "/login" do |env| end sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user = create_user(sid, email, password) + user, sid = create_user(sid, email, password) user_array = user.to_a - user_array[5] = user_array[5].to_json + user_array[4] = user_array[4].to_json args = arg_array(user_array) PG_DB.exec("INSERT INTO users VALUES (#{args})", user_array) + PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.now) view_name = "subscriptions_#{sha256(user.email)[0..7]}" PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \ @@ -1078,7 +1080,7 @@ get "/signout" do |env| user = env.get("user").as(User) sid = env.get("sid").as(String) - PG_DB.exec("UPDATE users SET id = array_remove(id, $1) WHERE email = $2", sid, user.email) + PG_DB.exec("DELETE FROM session_ids * WHERE id = $1", sid) env.request.cookies.each do |cookie| cookie.expires = Time.new(1990, 1, 1) @@ -1252,7 +1254,7 @@ get "/mark_watched" do |env| if user user = user.as(User) if !user.watched.includes? id - PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE $2 = id", [id], user.id) + PG_DB.exec("UPDATE users SET watched = watched || $1 WHERE email = $2", [id], user.email) end end @@ -1347,9 +1349,10 @@ get "/subscription_manager" do |env| locale = LOCALES[env.get("locale").as(String)]? user = env.get? "user" + sid = env.get? "sid" referer = get_referer(env, "/") - if !user + if !user && !sid next env.redirect referer end @@ -1360,7 +1363,7 @@ get "/subscription_manager" do |env| headers = HTTP::Headers.new headers["Cookie"] = env.request.headers["Cookie"] - user = get_user(user.id[0], headers, PG_DB) + user, sid = get_user(sid, headers, PG_DB) end action_takeout = env.params.query["action_takeout"]?.try &.to_i? @@ -1370,14 +1373,7 @@ get "/subscription_manager" do |env| format = env.params.query["format"]? format ||= "rss" - subscriptions = [] of InvidiousChannel - user.subscriptions.each do |ucid| - begin - subscriptions << get_channel(ucid, PG_DB, false, false) - rescue ex - next - end - end + subscriptions = PG_DB.query_all("SELECT * FROM channels WHERE id = ANY('{#{user.subscriptions.join(",")}}')", as: InvidiousChannel) subscriptions.sort_by! { |channel| channel.author.downcase } if action_takeout @@ -1756,10 +1752,12 @@ get "/feed/subscriptions" do |env| locale = LOCALES[env.get("locale").as(String)]? user = env.get? "user" + sid = env.get? "sid" referer = get_referer(env) if user user = user.as(User) + sid = sid.as(String) preferences = user.preferences if preferences.unseen_only @@ -1771,7 +1769,7 @@ get "/feed/subscriptions" do |env| headers["Cookie"] = env.request.headers["Cookie"] if !user.password - user = get_user(user.id[0], headers, PG_DB) + user, sid = get_user(sid, headers, PG_DB) end max_results = preferences.max_results @@ -3033,7 +3031,8 @@ end ucid = env.params.url["ucid"] page = env.params.query["page"]?.try &.to_i? page ||= 1 - sort_by = env.params.query["sort_by"]?.try &.downcase + sort_by = env.params.query["sort"]?.try &.downcase + sort_by ||= env.params.query["sort_by"]?.try &.downcase sort_by ||= "newest" begin @@ -3438,7 +3437,7 @@ get "/api/v1/mixes/:rdid" do |env| rdid = env.params.url["rdid"] continuation = env.params.query["continuation"]? - continuation ||= rdid.lchop("RD") + continuation ||= rdid.lchop("RD")[0, 11] format = env.params.query["format"]? format ||= "json" @@ -3662,6 +3661,8 @@ get "/latest_version" do |env| id = env.params.query["id"]? itag = env.params.query["itag"]? + region = env.params.query["region"]? + local = env.params.query["local"]? local ||= "false" local = local == "true" @@ -3670,7 +3671,7 @@ get "/latest_version" do |env| halt env, status_code: 400 end - video = get_video(id, PG_DB, proxies) + video = get_video(id, PG_DB, proxies, region: region) fmt_stream = video.fmt_stream(decrypt_function) adaptive_fmts = video.adaptive_fmts(decrypt_function) @@ -3943,14 +3944,13 @@ end error 500 do |env| error_message = <<-END_HTML - Looks like you've found a bug in Invidious. Feel free to open a new issue - <a href="https://github.com/omarroth/invidious/issues/github.com/omarroth/invidious"> + Looks like you've found a bug in Invidious. Feel free to open a new issue + <a href="https://github.com/omarroth/invidious/issues"> here </a> or send an email to <a href="mailto:omarroth@protonmail.com"> - omarroth@protonmail.com - </a>. + omarroth@protonmail.com</a>. END_HTML templated "error" end diff --git a/src/invidious/channels.cr b/src/invidious/channels.cr index ccaf2487..b6692919 100644 --- a/src/invidious/channels.cr +++ b/src/invidious/channels.cr @@ -260,6 +260,132 @@ def produce_channel_videos_url(ucid, page = 1, auto_generated = nil, sort_by = " return url end +def produce_channel_playlists_url(ucid, cursor, sort = "newest", auto_generated = false) + if !auto_generated + cursor = Base64.urlsafe_encode(cursor, false) + end + + meta = IO::Memory.new + + if auto_generated + meta.write(Bytes[0x08, 0x0a]) + end + + meta.write(Bytes[0x12, 0x09]) + meta.print("playlists") + + if auto_generated + meta.write(Bytes[0x20, 0x32]) + else + # TODO: Look at 0x01, 0x00 + case sort + when "oldest", "oldest_created" + meta.write(Bytes[0x18, 0x02]) + when "newest", "newest_created" + meta.write(Bytes[0x18, 0x03]) + when "last", "last_added" + meta.write(Bytes[0x18, 0x04]) + end + + meta.write(Bytes[0x20, 0x01]) + end + + meta.write(Bytes[0x30, 0x02]) + meta.write(Bytes[0x38, 0x01]) + meta.write(Bytes[0x60, 0x01]) + meta.write(Bytes[0x6a, 0x00]) + + meta.write(Bytes[0x7a, cursor.size]) + meta.print(cursor) + + meta.write(Bytes[0xb8, 0x01, 0x00]) + + meta.rewind + meta = Base64.urlsafe_encode(meta.to_slice) + meta = URI.escape(meta) + + continuation = IO::Memory.new + continuation.write(Bytes[0x12, ucid.size]) + continuation.print(ucid) + + continuation.write(Bytes[0x1a]) + continuation.write(write_var_int(meta.size)) + continuation.print(meta) + + continuation.rewind + continuation = continuation.gets_to_end + + wrapper = IO::Memory.new + wrapper.write(Bytes[0xe2, 0xa9, 0x85, 0xb2, 0x02]) + wrapper.write(write_var_int(continuation.size)) + wrapper.print(continuation) + wrapper.rewind + + wrapper = Base64.urlsafe_encode(wrapper.to_slice) + wrapper = URI.escape(wrapper) + + url = "/browse_ajax?continuation=#{wrapper}&gl=US&hl=en" + + return url +end + +def extract_channel_playlists_cursor(url, auto_generated) + wrapper = HTTP::Params.parse(URI.parse(url).query.not_nil!)["continuation"] + + wrapper = URI.unescape(wrapper) + wrapper = Base64.decode(wrapper) + + # 0xe2 0xa9 0x85 0xb2 0x02 + wrapper += 5 + + continuation_size = read_var_int(wrapper[0, 4]) + wrapper += write_var_int(continuation_size).size + continuation = wrapper[0, continuation_size] + + # 0x12 + continuation += 1 + ucid_size = continuation[0] + continuation += 1 + ucid = continuation[0, ucid_size] + continuation += ucid_size + + # 0x1a + continuation += 1 + meta_size = read_var_int(continuation[0, 4]) + continuation += write_var_int(meta_size).size + meta = continuation[0, meta_size] + continuation += meta_size + + meta = String.new(meta) + meta = URI.unescape(meta) + meta = Base64.decode(meta) + + # 0x12 0x09 playlists + meta += 11 + + until meta[0] == 0x7a + tag = read_var_int(meta[0, 4]) + meta += write_var_int(tag).size + value = meta[0] + meta += 1 + end + + # 0x7a + meta += 1 + cursor_size = meta[0] + meta += 1 + cursor = meta[0, cursor_size] + + cursor = String.new(cursor) + + if !auto_generated + cursor = URI.unescape(cursor) + cursor = Base64.decode_string(cursor) + end + + return cursor +end + def get_about_info(ucid, locale) client = make_client(YT_URL) @@ -290,7 +416,7 @@ def get_about_info(ucid, locale) sub_count ||= 0 author = about.xpath_node(%q(//span[contains(@class,"qualified-channel-title-text")]/a)).not_nil!.content - ucid = about.xpath_node(%q(//link[@rel="canonical"])).not_nil!["href"].split("/")[-1] + ucid = about.xpath_node(%q(//meta[@itemprop="channelId"])).not_nil!["content"] # Auto-generated channels # https://support.google.com/youtube/answer/2579942 diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 942757c3..45ebc4dd 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -166,35 +166,33 @@ def extract_videos(nodeset, ucid = nil) videos.map { |video| video.as(SearchVideo) } end -def extract_items(nodeset, ucid = nil) +def extract_items(nodeset, ucid = nil, author_name = nil) # TODO: Make this a 'common', so it makes more sense to be used here items = [] of SearchItem nodeset.each do |node| - anchor = node.xpath_node(%q(.//h3[contains(@class,"yt-lockup-title")]/a)) + anchor = node.xpath_node(%q(.//h3[contains(@class, "yt-lockup-title")]/a)) if !anchor next end + title = anchor.content.strip + id = anchor["href"] if anchor["href"].starts_with? "https://www.googleadservices.com" next end anchor = node.xpath_node(%q(.//div[contains(@class, "yt-lockup-byline")]/a)) - if !anchor - author = "" - author_id = "" - else + if anchor author = anchor.content.strip author_id = anchor["href"].split("/")[-1] end - anchor = node.xpath_node(%q(.//h3[contains(@class, "yt-lockup-title")]/a)) - if !anchor - next - end - title = anchor.content.strip - id = anchor["href"] + author ||= author_name + author_id ||= ucid + + author ||= "" + author_id ||= "" description_html = node.xpath_node(%q(.//div[contains(@class, "yt-lockup-description")])) description_html, description = html_to_content(description_html) @@ -354,3 +352,94 @@ def extract_items(nodeset, ucid = nil) return items end + +def extract_shelf_items(nodeset, ucid = nil, author_name = nil) + items = [] of SearchPlaylist + + nodeset.each do |shelf| + shelf_anchor = shelf.xpath_node(%q(.//h2[contains(@class, "branded-page-module-title")])) + + if !shelf_anchor + next + end + + title = shelf_anchor.xpath_node(%q(.//span[contains(@class, "branded-page-module-title-text")])) + if title + title = title.content.strip + end + title ||= "" + + id = shelf_anchor.xpath_node(%q(.//a)).try &.["href"] + if !id + next + end + + is_playlist = false + videos = [] of SearchPlaylistVideo + + shelf.xpath_nodes(%q(.//ul[contains(@class, "yt-uix-shelfslider-list")]/li)).each do |child_node| + type = child_node.xpath_node(%q(./div)) + if !type + next + end + + case type["class"] + when .includes? "yt-lockup-video" + is_playlist = true + + anchor = child_node.xpath_node(%q(.//h3[contains(@class, "yt-lockup-title")]/a)) + if anchor + video_title = anchor.content.strip + video_id = HTTP::Params.parse(URI.parse(anchor["href"]).query.not_nil!)["v"] + end + video_title ||= "" + video_id ||= "" + + anchor = child_node.xpath_node(%q(.//span[@class="video-time"])) + if anchor + length_seconds = decode_length_seconds(anchor.content) + end + length_seconds ||= 0 + + videos << SearchPlaylistVideo.new( + video_title, + video_id, + length_seconds + ) + when .includes? "yt-lockup-playlist" + anchor = child_node.xpath_node(%q(.//h3[contains(@class, "yt-lockup-title")]/a)) + if anchor + playlist_title = anchor.content.strip + params = HTTP::Params.parse(URI.parse(anchor["href"]).query.not_nil!) + plid = params["list"] + end + playlist_title ||= "" + plid ||= "" + + items << SearchPlaylist.new( + playlist_title, + plid, + author_name, + ucid, + 50, + Array(SearchPlaylistVideo).new + ) + end + end + + if is_playlist + plid = HTTP::Params.parse(URI.parse(id).query.not_nil!)["list"] + + items << SearchPlaylist.new( + title, + plid, + author_name, + ucid, + videos.size, + videos + ) + end + end + + return items +end diff --git a/src/invidious/mixes.cr b/src/invidious/mixes.cr index a56f468a..a3ada869 100644 --- a/src/invidious/mixes.cr +++ b/src/invidious/mixes.cr @@ -52,7 +52,10 @@ def fetch_mix(rdid, video_id, cookies = nil, locale = nil) item = item["playlistPanelVideoRenderer"] id = item["videoId"].as_s - title = item["title"]["simpleText"].as_s + title = item["title"]?.try &.["simpleText"].as_s + if !title + next + end author = item["longBylineText"]["runs"][0]["text"].as_s ucid = item["longBylineText"]["runs"][0]["navigationEndpoint"]["browseEndpoint"]["browseId"].as_s length_seconds = decode_length_seconds(item["lengthText"]["simpleText"].as_s) diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr index 220a0ef7..28f2e4ce 100644 --- a/src/invidious/playlists.cr +++ b/src/invidious/playlists.cr @@ -161,117 +161,6 @@ def produce_playlist_url(id, index) return url end -def produce_channel_playlists_url(ucid, cursor, sort = "newest") - cursor = Base64.urlsafe_encode(cursor, false) - - meta = IO::Memory.new - meta.write(Bytes[0x12, 0x09]) - meta.print("playlists") - - # TODO: Look at 0x01, 0x00 - case sort - when "oldest", "oldest_created" - meta.write(Bytes[0x18, 0x02]) - when "newest", "newest_created" - meta.write(Bytes[0x18, 0x03]) - when "last", "last_added" - meta.write(Bytes[0x18, 0x04]) - end - - meta.write(Bytes[0x20, 0x01]) - meta.write(Bytes[0x30, 0x02]) - meta.write(Bytes[0x38, 0x01]) - meta.write(Bytes[0x60, 0x01]) - meta.write(Bytes[0x6a, 0x00]) - - meta.write(Bytes[0x7a, cursor.size]) - meta.print(cursor) - - meta.write(Bytes[0xb8, 0x01, 0x00]) - - meta.rewind - meta = Base64.urlsafe_encode(meta.to_slice) - meta = URI.escape(meta) - - continuation = IO::Memory.new - continuation.write(Bytes[0x12, ucid.size]) - continuation.print(ucid) - - continuation.write(Bytes[0x1a]) - continuation.write(write_var_int(meta.size)) - continuation.print(meta) - - continuation.rewind - continuation = continuation.gets_to_end - - wrapper = IO::Memory.new - wrapper.write(Bytes[0xe2, 0xa9, 0x85, 0xb2, 0x02]) - wrapper.write(write_var_int(continuation.size)) - wrapper.print(continuation) - wrapper.rewind - - wrapper = Base64.urlsafe_encode(wrapper.to_slice) - wrapper = URI.escape(wrapper) - - url = "/browse_ajax?continuation=#{wrapper}&gl=US&hl=en" - - return url -end - -def extract_channel_playlists_cursor(url) - wrapper = HTTP::Params.parse(URI.parse(url).query.not_nil!)["continuation"] - - wrapper = URI.unescape(wrapper) - wrapper = Base64.decode(wrapper) - - # 0xe2 0xa9 0x85 0xb2 0x02 - wrapper += 5 - - continuation_size = read_var_int(wrapper[0, 4]) - wrapper += write_var_int(continuation_size).size - continuation = wrapper[0, continuation_size] - - # 0x12 - continuation += 1 - ucid_size = continuation[0] - continuation += 1 - ucid = continuation[0, ucid_size] - continuation += ucid_size - - # 0x1a - continuation += 1 - meta_size = read_var_int(continuation[0, 4]) - continuation += write_var_int(meta_size).size - meta = continuation[0, meta_size] - continuation += meta_size - - meta = String.new(meta) - meta = URI.unescape(meta) - meta = Base64.decode(meta) - - # 0x12 0x09 playlists - meta += 11 - - until meta[0] == 0x7a - tag = read_var_int(meta[0, 4]) - meta += write_var_int(tag).size - value = meta[0] - meta += 1 - end - - # 0x7a - meta += 1 - cursor_size = meta[0] - meta += 1 - cursor = meta[0, cursor_size] - - cursor = String.new(cursor) - cursor = URI.unescape(cursor) - cursor = Base64.decode_string(cursor) - - return cursor -end - def fetch_playlist(plid, locale) client = make_client(YT_URL) diff --git a/src/invidious/users.cr b/src/invidious/users.cr index d45c5af4..072638ba 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -12,7 +12,6 @@ class User end add_mapping({ - id: Array(String), updated: Time, notifications: Array(String), subscriptions: Array(String), @@ -126,18 +125,21 @@ class Preferences end def get_user(sid, headers, db, refresh = true) - if db.query_one?("SELECT EXISTS (SELECT true FROM users WHERE $1 = ANY(id))", sid, as: Bool) - user = db.query_one("SELECT * FROM users WHERE $1 = ANY(id)", sid, as: User) + if email = db.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String) + user = db.query_one("SELECT * FROM users WHERE email = $1", email, as: User) if refresh && Time.now - user.updated > 1.minute - user = fetch_user(sid, headers, db) + user, sid = fetch_user(sid, headers, db) user_array = user.to_a - user_array[5] = user_array[5].to_json + user_array[4] = user_array[4].to_json args = arg_array(user_array) db.exec("INSERT INTO users VALUES (#{args}) \ - ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) + ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", user_array) + + db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \ + ON CONFLICT (id) DO NOTHING", sid, user.email, Time.now) begin view_name = "subscriptions_#{sha256(user.email)[0..7]}" @@ -149,14 +151,17 @@ def get_user(sid, headers, db, refresh = true) end end else - user = fetch_user(sid, headers, db) + user, sid = fetch_user(sid, headers, db) user_array = user.to_a - user_array[5] = user_array[5].to_json + user_array[4] = user_array[4].to_json args = arg_array(user.to_a) db.exec("INSERT INTO users VALUES (#{args}) \ - ON CONFLICT (email) DO UPDATE SET id = users.id || $1, updated = $2, subscriptions = $4", user_array) + ON CONFLICT (email) DO UPDATE SET updated = $1, subscriptions = $3", user_array) + + db.exec("INSERT INTO session_ids VALUES ($1,$2,$3) \ + ON CONFLICT (id) DO NOTHING", sid, user.email, Time.now) begin view_name = "subscriptions_#{sha256(user.email)[0..7]}" @@ -168,7 +173,7 @@ def get_user(sid, headers, db, refresh = true) end end - return user + return user, sid end def fetch_user(sid, headers, db) @@ -196,17 +201,17 @@ def fetch_user(sid, headers, db) token = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user = User.new([sid], Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String) - return user + user = User.new(Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String) + return user, sid end def create_user(sid, email, password) password = Crypto::Bcrypt::Password.create(password, cost: 10) token = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) - user = User.new([sid], Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String) + user = User.new(Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String) - return user + return user, sid end def create_response(user_id, operation, key, db, expire = 6.hours) diff --git a/src/invidious/views/components/subscribe_widget_script.ecr b/src/invidious/views/components/subscribe_widget_script.ecr index c5e36b79..e2994c86 100644 --- a/src/invidious/views/components/subscribe_widget_script.ecr +++ b/src/invidious/views/components/subscribe_widget_script.ecr @@ -20,7 +20,7 @@ function subscribe(timeouts = 0) { var fallback = subscribe_button.innerHTML; subscribe_button.onclick = unsubscribe; - subscribe_button.innerHTML = '<b><%= translate(locale, "Unsubscribe") %> | <%= sub_count_text %></b>' + subscribe_button.innerHTML = '<b><%= translate(locale, "Unsubscribe").gsub("'", "\\'") %> | <%= sub_count_text %></b>' xhr.onreadystatechange = function() { if (xhr.readyState == 4) { @@ -55,7 +55,7 @@ function unsubscribe(timeouts = 0) { var fallback = subscribe_button.innerHTML; subscribe_button.onclick = subscribe; - subscribe_button.innerHTML = '<b><%= translate(locale, "Subscribe") %> | <%= sub_count_text %></b>' + subscribe_button.innerHTML = '<b><%= translate(locale, "Subscribe").gsub("'", "\\'") %> | <%= sub_count_text %></b>' xhr.onreadystatechange = function() { if (xhr.readyState == 4) { |
