diff --git a/api/instagram.go b/api/instagram.go
deleted file mode 100644
index 0b6d6b0..0000000
--- a/api/instagram.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package api
-
-type IgReel struct {
- Items []IgReelItem
-}
-
-type IgUser struct {
- Username string
- FullName string `json:"full_name"`
-}
-
-type IgReelItem struct {
- Code string
- User IgUser
- Caption IgCaption
- VideoDuration float64 `json:"video_duration"`
- VideoVersions []IgReelVideo `json:"video_versions"`
- ClipsMetadata IgReelClipsMetadata `json:"clips_metadata"`
-}
-
-type IgReelVideo struct {
- Width int
- Height int
- URL string
-}
-
-type IgCaption struct {
- Text string
-}
-
-type IgReelClipsMetadata struct {
- MusicInfo *IgReelMusicInfo `json:"music_info"`
- OriginalSoundInfo *IgReelOriginalSoundInfo `json:"original_sound_info"`
-}
-
-type IgReelMusicInfo struct {
- MusicAssetInfo IgReelMusicAssetInfo `json:"music_asset_info"`
-}
-
-type IgReelMusicAssetInfo struct {
- DisplayArtist string `json:"display_artist"`
- Title string
- ProgressiveDownloadURL string `json:"progressive_download_url"`
-}
-
-type IgReelOriginalSoundInfo struct {
- ProgressiveDownloadURL string `json:"progressive_download_url"`
-}
diff --git a/api/instagram_api.go b/api/instagram_api.go
deleted file mode 100644
index 27a242b..0000000
--- a/api/instagram_api.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package api
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "regexp"
-
- "github.com/ailinykh/pullanusbot/v2/core"
-)
-
-// CreateInstagramAPI
-func CreateInstagramAPI(l core.ILogger, cookie string) InstAPI {
- return &InstagramAPI{l, cookie}
-}
-
-type InstAPI interface {
- GetReel(string) (*IgReel, error)
-}
-
-// Instagram API
-type InstagramAPI struct {
- l core.ILogger
- cookie string
-}
-
-func (api *InstagramAPI) GetReel(urlString string) (*IgReel, error) {
- body, err := api.getContent(urlString, map[string]string{
- "sec-fetch-mode": "navigate",
- "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
- "cookie": api.cookie,
- "accept": "text/html",
- })
- if err != nil {
- api.l.Error(err)
- return nil, err
- }
-
- // os.WriteFile("instagram-reel.html", body, 0644)
-
- r := regexp.MustCompile(`"xdt_api__v1__media__shortcode__web_info":(.*)\},"extensions"`)
- match := r.FindSubmatch(body)
- if len(match) < 2 {
- return nil, fmt.Errorf("parse HTML failed: %s", urlString)
- }
-
- // os.WriteFile("instagram-reel.json", match[1], 0644)
-
- var reel IgReel
- err = json.Unmarshal(match[1], &reel)
- if err != nil {
- api.l.Error(err)
- return nil, err
- }
-
- return &reel, nil
-}
-
-func (api *InstagramAPI) getContent(urlString string, headers map[string]string) ([]byte, error) {
- req, err := http.NewRequest("GET", urlString, nil)
-
- for k, v := range headers {
- req.Header.Set(k, v)
- }
-
- if err != nil {
- api.l.Error(err)
- return nil, err
- }
-
- resp, err := http.DefaultClient.Do(req)
- if err != nil {
- api.l.Error(err)
- return nil, err
- }
- defer resp.Body.Close()
- return ioutil.ReadAll(resp.Body)
-}
diff --git a/api/tiktok_media_factory.go b/api/tiktok_media_factory.go
index 01b61c5..cdf3a47 100644
--- a/api/tiktok_media_factory.go
+++ b/api/tiktok_media_factory.go
@@ -16,7 +16,7 @@ type TikTokMediaFactory struct {
}
func (factory *TikTokMediaFactory) CreateMedia(url string) ([]*core.Media, error) {
- item, err := factory.api.get(url)
+ item, err := factory.api.Get(url)
if err != nil {
factory.l.Error(err)
return nil, err
diff --git a/api/youtube_media_factory.go b/api/youtube_media_factory.go
index fdb2104..79ec2c2 100644
--- a/api/youtube_media_factory.go
+++ b/api/youtube_media_factory.go
@@ -22,7 +22,7 @@ type YoutubeMediaFactory struct {
// CreateMedia is a core.IMediaFactory interface implementation
func (y *YoutubeMediaFactory) CreateMedia(url string) ([]*core.Media, error) {
- resp, err := y.api.get(url)
+ resp, err := y.api.Get(url)
if err != nil {
y.l.Error(err)
return nil, err
@@ -73,7 +73,7 @@ func (y *YoutubeMediaFactory) getFormats(resp *YtDlpResponse) (*YtDlpFormat, *Yt
// CreateVideo is a core.IVideoFactory interface implementation
func (y *YoutubeMediaFactory) CreateVideo(id string) (*core.Video, error) {
- resp, err := y.api.get(id)
+ resp, err := y.api.Get(id)
if err != nil {
y.l.Error(err)
return nil, err
diff --git a/api/ytdlp_api.go b/api/ytdlp_api.go
index 83340c1..027a4e5 100644
--- a/api/ytdlp_api.go
+++ b/api/ytdlp_api.go
@@ -10,7 +10,7 @@ import (
)
type YoutubeApi interface {
- get(string) (*YtDlpResponse, error)
+ Get(string) (*YtDlpResponse, error)
}
func CreateYtDlpApi(cookie string, l core.ILogger) YoutubeApi {
@@ -22,7 +22,7 @@ type YtDlpApi struct {
l core.ILogger
}
-func (api *YtDlpApi) get(url string) (*YtDlpResponse, error) {
+func (api *YtDlpApi) Get(url string) (*YtDlpResponse, error) {
args := []string{
"--quiet",
"--no-warnings",
diff --git a/pullanusbot.go b/pullanusbot.go
index 5e72eca..8c49b26 100644
--- a/pullanusbot.go
+++ b/pullanusbot.go
@@ -100,9 +100,8 @@ func main() {
iDoNotCare := usecases.CreateIDoNotCare()
telebot.AddHandler(iDoNotCare)
- instaAPI := api.CreateInstagramAPI(logger, os.Getenv("INSTAGRAM_COOKIE"))
- downloadVideoFactory := helpers.CreateDownloadVideoFactory(logger, fileDownloader, converter)
- instaFlow := usecases.CreateInstagramFlow(logger, instaAPI, downloadVideoFactory, localMediaSender, sendVideoStrategySplitDecorator)
+ instaAPI := api.CreateYtDlpApi(path.Join(getWorkingDir(), "cookies.txt"), logger)
+ instaFlow := usecases.CreateInstagramFlow(logger, instaAPI, localMediaSender)
removeInstaSourceDecorator := usecases.CreateRemoveSourceDecorator(logger, instaFlow, core.SInstagramFlowRemoveSource, boolSettingProvider)
telebot.AddHandler(removeInstaSourceDecorator)
diff --git a/usecases/instagram_flow.go b/usecases/instagram_flow.go
index 8822788..fd7f167 100644
--- a/usecases/instagram_flow.go
+++ b/usecases/instagram_flow.go
@@ -9,16 +9,14 @@ import (
"github.com/ailinykh/pullanusbot/v2/core"
)
-func CreateInstagramFlow(l core.ILogger, api api.InstAPI, createVideo core.IVideoFactory, sendMedia core.ISendMediaStrategy, sendVideo core.ISendVideoStrategy) core.ITextHandler {
- return &InstagramFlow{l, api, createVideo, sendMedia, sendVideo}
+func CreateInstagramFlow(l core.ILogger, api api.YoutubeApi, sendMedia core.ISendMediaStrategy) core.ITextHandler {
+ return &InstagramFlow{l, api, sendMedia}
}
type InstagramFlow struct {
- l core.ILogger
- api api.InstAPI
- createVideo core.IVideoFactory
- sendMedia core.ISendMediaStrategy
- sendVideo core.ISendVideoStrategy
+ l core.ILogger
+ api api.YoutubeApi
+ sendMedia core.ISendMediaStrategy
}
// HandleText is a core.ITextHandler protocol implementation
@@ -56,23 +54,13 @@ func (flow *InstagramFlow) HandleText(message *core.Message, bot core.IBot) erro
func (flow *InstagramFlow) handleReel(url string, message *core.Message, bot core.IBot) error {
flow.l.Infof("processing %s", url)
- reel, err := flow.api.GetReel(url)
+ resp, err := flow.api.Get(url)
if err != nil {
flow.l.Error(err)
return err
}
- if len(reel.Items) < 1 {
- return fmt.Errorf("insufficient reel items")
- }
-
- item := reel.Items[0]
-
- caption := item.Caption.Text
- if info := item.ClipsMetadata.MusicInfo; info != nil {
- caption = fmt.Sprintf("\nš¶ %s - %s\n\n%s", info.MusicAssetInfo.ProgressiveDownloadURL, info.MusicAssetInfo.DisplayArtist, info.MusicAssetInfo.Title, caption)
- }
- caption = fmt.Sprintf("š· %s (by %s)\n%s", url, item.User.FullName, message.Sender.DisplayName(), caption)
+ caption := fmt.Sprintf("š· %s (by %s)\n%s", url, resp.Uploader, message.Sender.DisplayName(), resp.Description)
if len(caption) > 1024 {
// strip by last space or line break if caption size limit exceeded
index := strings.LastIndex(caption[:1024], " ")
@@ -83,31 +71,31 @@ func (flow *InstagramFlow) handleReel(url string, message *core.Message, bot cor
caption = caption[:index]
}
- if item.VideoDuration < 360 { // apparently 6 min file takes less than 50 MB
- return flow.sendAsMedia(item, caption, message, bot)
- }
-
- video, err := flow.createVideo.CreateVideo(item.VideoVersions[0].URL)
+ vf, err := flow.getPreferredVideoFormat(resp)
if err != nil {
flow.l.Error(err)
return err
}
- defer video.Dispose()
- return flow.sendVideo.SendVideo(video, caption, bot)
+ media := core.Media{
+ Caption: caption,
+ ResourceURL: vf.Url,
+ URL: url,
+ }
+ return flow.sendMedia.SendMedia([]*core.Media{&media}, bot)
}
-func (flow *InstagramFlow) sendAsMedia(item api.IgReelItem, caption string, message *core.Message, bot core.IBot) error {
- media := &core.Media{
- ResourceURL: item.VideoVersions[0].URL,
- URL: "https://www.instagram.com/reel/" + item.Code + "/",
- Title: item.User.FullName,
- Caption: caption,
+func (flow *InstagramFlow) getPreferredVideoFormat(resp *api.YtDlpResponse) (*api.YtDlpFormat, error) {
+ idx := -1
+ for i, f := range resp.Formats {
+ if strings.HasPrefix(f.FormatId, "dash-") {
+ continue
+ }
+ idx = i
}
- err := flow.sendMedia.SendMedia([]*core.Media{media}, bot)
- if err != nil {
- flow.l.Error(err)
+ if idx < 0 {
+ return nil, fmt.Errorf("no appropriate format found")
}
- return err
+ return resp.Formats[idx], nil
}