From fa28a2240686e6ba17c8a70210d073fb662113c4 Mon Sep 17 00:00:00 2001 From: Listen 1 Date: Fri, 26 Mar 2021 20:32:18 +0800 Subject: [PATCH] Login netease (#511) * feat: netease login page and basic login api * feat: add recommend playlist and i18n * feat: valid login form before submit * fix: not initial when login * style: fix input background/font in night mode * feat: support phone login * fix: remove extra console.log * refactor: move auth related to auth controller --- css/common.css | 100 +- i18n/en_US.json | 18 +- i18n/fr_FR.json | 18 +- i18n/zh_CN.json | 18 +- i18n/zh_TC.json | 18 +- images/netease-logo.png | Bin 0 -> 11223 bytes js/app.js | 156 +++ js/loweb.js | 17 + js/provider/netease.js | 156 +++ listen1.html | 2827 ++++++++++++++++++++------------------- 10 files changed, 1976 insertions(+), 1352 deletions(-) create mode 100644 images/netease-logo.png diff --git a/css/common.css b/css/common.css index 07c50e38..2523daf8 100644 --- a/css/common.css +++ b/css/common.css @@ -99,6 +99,7 @@ svg { height: 49px; border: 5px solid rgba(0, 0, 0, 0); background-clip: padding-box; + border-radius: 7px; -webkit-border-radius: 7px; background-color: var(--scroll-color); /*rgba(151, 151, 151, 0.4);*/ @@ -231,6 +232,9 @@ svg { height: 18px; color: var(--icon-default-color); } +.navigation .icon svg { + color: var(--text-default-color); +} .navigation .backfront { flex: 0 0 45px; line-height: 46px; @@ -788,6 +792,99 @@ ul.detail-songlist li .tools .icon { } /* page song detail end */ +/* page login start */ +.page .login { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: calc(100vh - 192px); +} +.page .login .login-logo { + margin-bottom: 16px; + display: flex; + align-items: center; +} +.page .login .login-logo img { + height: 64px; + margin: 20px; +} +.page .login .login-title { + font-size: 18px; + margin-bottom: 10px; +} +.page .login .login-form .login-form_field { + display: flex; + align-items: center; + height: 40px; + margin: 24px; + width: 270px; + border: solid 1px var(--button-background-color); +} +.page .login .login-form .login-form_field input { + background: var(--content-background-color); + color: var(--text-default-color); +} +.page .login .login-form .login-form_field input.login-form_field_countrycode { + flex: 0 0 40px; + width: 40px; +} +.page .login .login-form .login-form_field svg { + margin-left: 12px; + margin-right: 12px; + color: var(--icon-default-color); + width: 18px; + height: 18px; +} +.page .login .login-form .login-form_field input { + border: none; + flex: 1; + font-size: 16px; +} +.page .login .login-submit_button { + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + margin-top: 24px; + padding: 8px; + width: 270px; + cursor: pointer; + border: solid 1px var(--button-border-color); +} +.page .login .login-switcher { + margin-top: 24px; + cursor: pointer; +} +.page .login .login-notice { + width: 270px; + border-top: 1px solid var(--button-border-color); + margin-top: 30px; + padding-top: 12px; + font-size: 12px; + color: var(--text-subtitle-color); +} +.page .login .usercard { + display: flex; + align-items: center; + width: 300px; + border: solid 1px var(--button-border-color); +} +.page .login .usercard img { + width: 60px; + margin: 10px; +} +.page .login .usercard .usercard-title { + flex: 1; + height: 50px; + font-size: 16px; + font-weight: 700; +} +.page .login .usercard button { + margin: 10px; +} +/* page login end */ + /* page setting start */ .page .settings-title { border-bottom: solid 1px var(--line-default-color); @@ -1428,7 +1525,7 @@ svg.searchspinner { /* widget source-list start */ .source-list { - margin: 20px 26px 0 26px; + margin: 20px 26px 10px 26px; } .source-list .source-button { @@ -1466,7 +1563,6 @@ svg.searchspinner { .playlist-filter .filter-item { padding: 5px 15px; margin-right: 10px; - margin-top: 10px; } .playlist-filter .filter-item.active { diff --git a/i18n/en_US.json b/i18n/en_US.json index 049e2db6..0d6748c0 100755 --- a/i18n/en_US.json +++ b/i18n/en_US.json @@ -118,5 +118,21 @@ "_CLOSE_TAB_ACTION": "Close tab action", "_VALID_AFTER_RESTART": "Valid after restart", "_QUIT_APPLICATION": "Quit Application", - "_MINIMIZE_TO_BACKGROUND": "Minimize to background" + "_MINIMIZE_TO_BACKGROUND": "Minimize to background", + "_MY_PLAYLIST": "My Playlist", + "_RECOMMEND_PLAYLIST": "Recommend Playlist", + "_LISTEN1_LOGIN_NOTICE": "Listen1 WILL NOT transfer your account data to any server other than music platform server.", + "_PASSWORD": "Password", + "_LOGIN": "Login", + "_LOGOUT": "Logout", + "_LOGIN_ERROR": "Login error, please check user name and password", + "_LOGIN_EMAIL_ERROR": "Please enter correct email address", + "_LOGIN_COUNTRYCODE_ERROR": "Please enter correct country code", + "_LOGIN_PHONE_ERROR": "Please enter correct phone number", + "_LOGIN_PASSWORD_ERROR": "Password can't be empty", + "_LOGIN_NETEASE": "Login Netease", + "_LOGIN_BY_MOBILE_PHONE": "Login by mobile phone", + "_LOGIN_BY_EMAIL": "Login by email", + "_MOBILE_PHONE": "Mobile Phone", + "_MY_NETEASE": "My Netease" } diff --git a/i18n/fr_FR.json b/i18n/fr_FR.json index 85a9329c..8273edff 100644 --- a/i18n/fr_FR.json +++ b/i18n/fr_FR.json @@ -118,5 +118,21 @@ "_CLOSE_TAB_ACTION": "Close tab action", "_VALID_AFTER_RESTART": "Valid after restart", "_QUIT_APPLICATION": "Quit Application", - "_MINIMIZE_TO_BACKGROUND": "Minimize to background" + "_MINIMIZE_TO_BACKGROUND": "Minimize to background", + "_MY_PLAYLIST": "My Playlist", + "_RECOMMEND_PLAYLIST": "Recommend Playlist", + "_LISTEN1_LOGIN_NOTICE": "Listen1 NE transférera PAS les données de votre compte vers un serveur autre que le serveur de la plate-forme musicale.", + "_PASSWORD": "Password", + "_LOGIN": "Login", + "_LOGOUT": "Logout", + "_LOGIN_ERROR": "Login error, please check user name and password", + "_LOGIN_EMAIL_ERROR": "Please enter correct email address", + "_LOGIN_COUNTRYCODE_ERROR": "Please enter correct country code", + "_LOGIN_PHONE_ERROR": "Please enter correct phone number", + "_LOGIN_PASSWORD_ERROR": "Password can't be empty", + "_LOGIN_NETEASE": "Login Netease", + "_LOGIN_BY_MOBILE_PHONE": "Login by mobile phone", + "_LOGIN_BY_EMAIL": "Login by email", + "_MOBILE_PHONE": "Mobile Phone", + "_MY_NETEASE": "My Netease" } diff --git a/i18n/zh_CN.json b/i18n/zh_CN.json index 7bb2f939..c2df934f 100755 --- a/i18n/zh_CN.json +++ b/i18n/zh_CN.json @@ -119,5 +119,21 @@ "_CLOSE_TAB_ACTION": "关闭标签页时行为", "_VALID_AFTER_RESTART": "需重启生效", "_QUIT_APPLICATION": "退出应用", - "_MINIMIZE_TO_BACKGROUND": "最小化到后台" + "_MINIMIZE_TO_BACKGROUND": "最小化到后台", + "_MY_PLAYLIST": "我的歌单", + "_RECOMMEND_PLAYLIST": "推荐歌单", + "_LISTEN1_LOGIN_NOTICE": "Listen1不会传输你的账号数据到任何非音乐平台官方的服务器。", + "_PASSWORD": "密码", + "_LOGIN": "登录", + "_LOGOUT": "退出登录", + "_LOGIN_ERROR": "登录失败,请检查用户名和密码", + "_LOGIN_EMAIL_ERROR": "请输入正确的邮箱地址", + "_LOGIN_COUNTRYCODE_ERROR": "请输入正确的国家或地区代码", + "_LOGIN_PHONE_ERROR": "请输入正确的手机号", + "_LOGIN_PASSWORD_ERROR": "密码不能为空", + "_LOGIN_NETEASE": "登录网易云音乐", + "_LOGIN_BY_MOBILE_PHONE": "手机号登录", + "_LOGIN_BY_EMAIL": "邮箱登录", + "_MOBILE_PHONE": "手机号", + "_MY_NETEASE": "我的网易云音乐" } diff --git a/i18n/zh_TC.json b/i18n/zh_TC.json index 82e4137b..d3dddca7 100644 --- a/i18n/zh_TC.json +++ b/i18n/zh_TC.json @@ -118,5 +118,21 @@ "_CLOSE_TAB_ACTION": "關閉標籤頁時行為", "_VALID_AFTER_RESTART": "需重載生效", "_QUIT_APPLICATION": "退出軟體", - "_MINIMIZE_TO_BACKGROUND": "最小化到後臺" + "_MINIMIZE_TO_BACKGROUND": "最小化到後臺", + "_MY_PLAYLIST": "我的歌單", + "_RECOMMEND_PLAYLIST": "推薦歌單", + "_LISTEN1_LOGIN_NOTICE": "Listen1不會傳輸你的賬號數據到任何非音樂平台官方的伺服器。", + "_PASSWORD": "密碼", + "_LOGIN": "登錄", + "_LOGOUT": "退出登錄", + "_LOGIN_ERROR": "登錄失敗,請檢查用戶名和密碼", + "_LOGIN_EMAIL_ERROR": "請輸入正確的郵箱地址", + "_LOGIN_COUNTRYCODE_ERROR": "請輸入正確的國家或地區代碼", + "_LOGIN_PHONE_ERROR": "請輸入正確的手機號", + "_LOGIN_PASSWORD_ERROR": "密碼不能為空", + "_LOGIN_NETEASE": "登錄網易雲音樂", + "_LOGIN_BY_MOBILE_PHONE": "手機號登錄", + "_LOGIN_BY_EMAIL": "郵箱登錄", + "_MOBILE_PHONE": "手機號", + "_MY_NETEASE": "我的網易雲音樂" } diff --git a/images/netease-logo.png b/images/netease-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b14f263db1221992ce909ad711566f8856eeb6f8 GIT binary patch literal 11223 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 { }, ]); + app.controller('AuthController', [ + '$scope', + '$translate', + ($scope, $translate) => { + $scope.loginProgress = false; + $scope.loginType = 'email'; + + $scope.setLoginType = (newType) => { + $scope.loginType = newType; + if (newType === 'phone') { + document.getElementById('login-countrycode').value = '+86'; + } + }; + // valid email/password + function validateEmail(email_str) { + const re = /\S+@\S+\.\S+/; + return re.test(email_str); + } + function validatePhone(phone_str) { + const re = /^[0-9]{7,16}$/; + return re.test(phone_str); + } + function validateCountrycode(countrycode_str) { + const re = /^\+[0-9]{1,4}$/; + return re.test(countrycode_str); + } + function validatePassword(password_str) { + return password_str !== ''; + } + $scope.login = (source) => { + let options = {}; + if ($scope.loginType === 'email') { + const email = document.getElementById('login-email').value; + const password = document.getElementById('login-password').value; + + if (!validateEmail(email)) { + return Notification.warning( + $translate.instant('_LOGIN_EMAIL_ERROR') + ); + } + if (!validatePassword(password)) { + return Notification.warning( + $translate.instant('_LOGIN_PASSWORD_ERROR') + ); + } + options = { + type: $scope.loginType, + email, + password, + }; + } else if ($scope.loginType === 'phone') { + const countrycode = document.getElementById('login-countrycode') + .value; + + const phone = document.getElementById('login-phone').value; + const password = document.getElementById('login-password').value; + if (!validateCountrycode(countrycode)) { + return Notification.warning( + $translate.instant('_LOGIN_COUNTRYCODE_ERROR') + ); + } + if (!validatePhone(phone)) { + return Notification.warning( + $translate.instant('_LOGIN_PHONE_ERROR') + ); + } + if (!validatePassword(password)) { + return Notification.warning( + $translate.instant('_LOGIN_PASSWORD_ERROR') + ); + } + options = { + type: $scope.loginType, + phone, + countrycode: countrycode.slice(1), + password, + }; + } else { + return Notification.error('not support login type'); + } + $scope.loginProgress = true; + return MediaService.login(source, options).success((data) => { + $scope.loginProgress = false; + if (data.status === 'success') { + $scope.setMusicAuth(source, data.data); + } else { + Notification.error($translate.instant('_LOGIN_ERROR')); + } + }); + }; + + $scope.logout = (source) => { + $scope.setMusicAuth(source, {}); + // TODO: clear cookie + }; + + $scope.is_login = (source) => + $scope.musicAuth[source] && $scope.musicAuth[source].is_login; + + $scope.musicAuth = localStorage.getObject('music_auth') || {}; + + $scope.setMusicAuth = (source, data) => { + $scope.musicAuth[source] = data; + localStorage.setObject('music_auth', $scope.musicAuth); + }; + }, + ]); + // control main view of page, it can be called any place app.controller('NavigationController', [ '$scope', @@ -2003,6 +2111,54 @@ const main = () => { }, ]); + const platformSourceList = [ + { + name: 'my_playlist', + displayId: '_MY_PLAYLIST', + }, + { + name: 'recommend_playlist', + displayId: '_RECOMMEND_PLAYLIST', + }, + ]; + + app.controller('PlatformController', [ + '$scope', + ($scope) => { + $scope.myPlatformPlaylists = []; + $scope.myPlatformUser = {}; + $scope.platformSourceList = platformSourceList; + $scope.tab = platformSourceList[0].name; + + $scope.loadPlatformPlaylists = () => { + if ($scope.myPlatformUser.platform === undefined) { + return; + } + let getPlaylistFn = MediaService.getUserPlaylist; + if ($scope.tab === 'recommend_playlist') { + getPlaylistFn = MediaService.getRecommendPlaylist; + } + const user = $scope.myPlatformUser; + getPlaylistFn(user.platform, { + user_id: user.user_id, + }).success((response) => { + const { data } = response; + $scope.myPlatformPlaylists = data.playlists; + }); + }; + + $scope.initPlatformController = (user) => { + $scope.myPlatformUser = user; + $scope.loadPlatformPlaylists(); + }; + + $scope.changePlatformTab = (name) => { + $scope.tab = name; + $scope.loadPlatformPlaylists(); + }; + }, + ]); + app.controller('PlayListController', [ '$scope', '$timeout', diff --git a/js/loweb.js b/js/loweb.js index e9ef26f3..9576adfb 100644 --- a/js/loweb.js +++ b/js/loweb.js @@ -339,6 +339,23 @@ const MediaService = { provider.bootstrap_track(sound, track, successCallback, failureCallback); }, + login(source, options) { + const url = `/login?${queryStringify(options)}`; + const provider = getProviderByName(source); + + return provider.login(url); + }, + getUserPlaylist(source, options) { + const provider = getProviderByName(source); + const url = `/get_user_playlist?${queryStringify(options)}`; + + return provider.get_user_playlist(url); + }, + getRecommendPlaylist(source) { + const provider = getProviderByName(source); + + return provider.get_recommend_playlist(); + }, }; // eslint-disable-next-line no-unused-vars diff --git a/js/provider/netease.js b/js/provider/netease.js index bef13507..e866ca01 100644 --- a/js/provider/netease.js +++ b/js/provider/netease.js @@ -706,6 +706,159 @@ function build_netease() { }; } + function ne_login(url) { + // use chrome extension to modify referer. + let target_url = 'https://music.163.com/weapi/login'; + const loginType = getParameterByName('type', url); + + const password = getParameterByName('password', url); + + let req_data = {}; + if (loginType === 'email') { + const email = getParameterByName('email', url); + + req_data = { + username: email, + password: forge.md5 + .create() + .update(forge.util.encodeUtf8(password)) + .digest() + .toHex(), + rememberLogin: 'true', + }; + } else if (loginType === 'phone') { + target_url = `https://music.163.com/weapi/login/cellphone`; + const countrycode = getParameterByName('countrycode', url); + const phone = getParameterByName('phone', url); + req_data = { + phone, + countrycode, + password: forge.md5 + .create() + .update(forge.util.encodeUtf8(password)) + .digest() + .toHex(), + rememberLogin: 'true', + }; + } + + const encrypt_req_data = _encrypted_request(req_data); + const expire = + (new Date().getTime() + 1e3 * 60 * 60 * 24 * 365 * 100) / 1000; + + cookieSet( + { + url: 'https://music.163.com', + name: 'os', + value: 'pc', + expirationDate: expire, + }, + (cookie) => {} + ); + return { + success(fn) { + axios + .post(target_url, new URLSearchParams(encrypt_req_data)) + .then((response) => { + const { data } = response; + const result = { + is_login: true, + user_id: data.account.id, + user_name: data.account.userName, + nickname: data.profile.nickname, + avatar: data.profile.avatarUrl, + platform: 'netease', + data, + }; + return fn({ + status: 'success', + data: result, + }); + }) + .catch(() => + fn({ + status: 'fail', + data: {}, + }) + ); + }, + }; + } + + function ne_get_user_playlist(url) { + const user_id = getParameterByName('user_id', url); + const target_url = 'https://music.163.com/api/user/playlist'; + + const req_data = { + uid: user_id, + limit: 1000, + offset: 0, + includeVideo: true, + }; + + return { + success(fn) { + axios + .post(target_url, new URLSearchParams(req_data)) + .then((response) => { + const playlists = []; + response.data.playlist.forEach((item) => { + const playlist = { + cover_img_url: item.coverImgUrl, + id: `neplaylist_${item.id}`, + source_url: `https://music.163.com/#/playlist?id=${item.id}`, + title: item.name, + }; + playlists.push(playlist); + }); + return fn({ + status: 'success', + data: { + playlists, + }, + }); + }); + }, + }; + } + + function ne_get_recommend_playlist() { + const target_url = 'https://music.163.com/weapi/personalized/playlist'; + + const req_data = { + limit: 30, + total: true, + n: 1000, + }; + + const encrypt_req_data = _encrypted_request(req_data); + + return { + success(fn) { + axios + .post(target_url, new URLSearchParams(encrypt_req_data)) + .then((response) => { + const playlists = []; + response.data.result.forEach((item) => { + const playlist = { + cover_img_url: item.picUrl, + id: `neplaylist_${item.id}`, + source_url: `https://music.163.com/#/playlist?id=${item.id}`, + title: item.name, + }; + playlists.push(playlist); + }); + return fn({ + status: 'success', + data: { + playlists, + }, + }); + }); + }, + }; + } + return { show_playlist: ne_show_playlist, get_playlist_filters, @@ -714,6 +867,9 @@ function build_netease() { bootstrap_track: ne_bootstrap_track, search: ne_search, lyric: ne_lyric, + login: ne_login, + get_user_playlist: ne_get_user_playlist, + get_recommend_playlist: ne_get_recommend_playlist, }; } diff --git a/listen1.html b/listen1.html index d384922d..ac4b2254 100644 --- a/listen1.html +++ b/listen1.html @@ -15,9 +15,7 @@ - -